C/C++ API Reference
Loading...
Searching...
No Matches
server.h
1// Copyright 2020 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#pragma once
15
16#include <cstddef>
17#include <tuple>
18
19#include "pw_containers/intrusive_list.h"
20#include "pw_rpc/channel.h"
21#include "pw_rpc/internal/call.h"
22#include "pw_rpc/internal/endpoint.h"
23#include "pw_rpc/internal/grpc.h"
24#include "pw_rpc/internal/lock.h"
25#include "pw_rpc/internal/method.h"
26#include "pw_rpc/internal/method_info.h"
27#include "pw_rpc/internal/server_call.h"
28#include "pw_rpc/service.h"
29#include "pw_span/span.h"
30#include "pw_status/status.h"
31
32namespace pw::rpc {
33
35
36class Server : public internal::Endpoint {
37 public:
38 // If dynamic allocation is supported, it is not necessary to preallocate a
39 // channels list.
40#if PW_RPC_DYNAMIC_ALLOCATION
41 _PW_RPC_CONSTEXPR Server() = default;
42#endif // PW_RPC_DYNAMIC_ALLOCATION
43
44 // Creates a client that uses a set of RPC channels. Channels can be shared
45 // between multiple clients and servers.
46 _PW_RPC_CONSTEXPR Server(span<Channel> channels) : Endpoint(channels) {}
47
48 // Registers one or more services with the server. This should not be called
49 // directly with a Service; instead, use a generated class which inherits
50 // from it.
51 //
52 // This function may be called with any number of services. Combining
53 // registration into fewer calls is preferred so the RPC mutex is only
54 // locked/unlocked once.
55 template <typename... OtherServices>
56 void RegisterService(Service& service, OtherServices&... services)
57 PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
58 internal::RpcLockGuard lock;
59 services_.push_front(service); // Register the first service
60
61 // Register any additional services by expanding the parameter pack. This
62 // is a fold expression of the comma operator.
63 (services_.push_front(services), ...);
64 }
65
66 // Returns whether a service is registered.
67 //
68 // Calling RegisterService with a registered service will assert. So depending
69 // on your logic you might want to check if a service is currently registered.
70 bool IsServiceRegistered(const Service& service) const
71 PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
72 internal::RpcLockGuard lock;
73
74 for (const Service& svc : services_) {
75 if (&svc == &service) {
76 return true;
77 }
78 }
79
80 return false;
81 }
82
83 template <typename... OtherServices>
84 void UnregisterService(Service& service, OtherServices&... services)
85 PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
86 internal::rpc_lock().lock();
87 UnregisterServiceLocked(service, static_cast<Service&>(services)...);
88 CleanUpCalls();
89 }
90
91 // Processes an RPC packet. The packet may contain an RPC request or a control
92 // packet, the result of which is processed in this function. Returns whether
93 // the packet was able to be processed:
94 //
95 // OK - The packet was processed by the server.
96 // DATA_LOSS - Failed to decode the packet.
97 // INVALID_ARGUMENT - The packet is intended for a client, not a server.
98 // UNAVAILABLE - No RPC channel with the requested ID was found.
99 Status ProcessPacket(ConstByteSpan packet_data)
100 PW_LOCKS_EXCLUDED(internal::rpc_lock());
101
102 private:
103 friend class internal::Call;
104 friend class ServerTestHelper;
105
106 // Give gRPC integration access to FindMethod and internal::Packet version of
107 // ProcessPacket
108 friend class pw::grpc::PwRpcHandler;
109
110 // Give call classes access to OpenCall.
111 friend class RawServerReaderWriter;
112 friend class RawServerWriter;
113 friend class RawServerReader;
114 friend class RawUnaryResponder;
115
116 template <typename, typename>
117 friend class NanopbServerReaderWriter;
118 template <typename>
119 friend class NanopbServerWriter;
120 template <typename, typename>
121 friend class NanopbServerReader;
122 template <typename>
123 friend class NanopbUnaryResponder;
124
125 template <typename, typename>
126 friend class PwpbServerReaderWriter;
127 template <typename>
128 friend class PwpbServerWriter;
129 template <typename, typename>
130 friend class PwpbServerReader;
131 template <typename>
132 friend class PwpbUnaryResponder;
133
134 // Opens a call object for an unrequested RPC. Calls created with OpenCall
135 // use a special call ID and will adopt the call ID from the first packet for
136 // their channel, service, and method. Only one call object may be opened in
137 // this fashion at a time.
138 //
139 // This function checks the type of RPC at compile time.
140 template <typename CallType,
141 auto kMethod,
142 MethodType kExpected,
143 typename ServiceImpl,
144 typename MethodImpl>
145 [[nodiscard]] CallType OpenCall(uint32_t channel_id,
146 ServiceImpl& service,
147 const MethodImpl& method)
148 PW_LOCKS_EXCLUDED(internal::rpc_lock()) {
149 internal::rpc_lock().lock();
150
151 using Info = internal::MethodInfo<kMethod>;
152 if constexpr (kExpected == MethodType::kUnary) {
153 static_assert(
154 Info::kType == kExpected,
155 "UnaryResponder objects may only be opened for unary RPCs.");
156 } else if constexpr (kExpected == MethodType::kServerStreaming) {
157 static_assert(
158 Info::kType == kExpected,
159 "ServerWriters may only be opened for server streaming RPCs.");
160 } else if constexpr (kExpected == MethodType::kClientStreaming) {
161 static_assert(
162 Info::kType == kExpected,
163 "ServerReaders may only be opened for client streaming RPCs.");
164 } else if constexpr (kExpected == MethodType::kBidirectionalStreaming) {
165 static_assert(Info::kType == kExpected,
166 "ServerReaderWriters may only be opened for bidirectional "
167 "streaming RPCs.");
168 }
169
170 CallType call(internal::CallContext(
171 *this, channel_id, service, method, internal::kOpenCallId)
172 .ClaimLocked());
173 CleanUpCalls();
174 return call;
175 }
176
177 std::tuple<Service*, const internal::Method*> FindMethod(uint32_t service_id,
178 uint32_t method_id)
179 PW_LOCKS_EXCLUDED(internal::rpc_lock());
180
181 std::tuple<Service*, const internal::Method*> FindMethodLocked(
182 uint32_t service_id, uint32_t method_id)
183 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock());
184
185 std::tuple<Service*, const internal::Method*> FindMethodLocked(
186 const internal::Packet& packet)
187 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock()) {
188 // Packets always include service and method IDs.
189 return FindMethodLocked(packet.service_id(), packet.method_id());
190 }
191
192 void HandleCompletionRequest(const internal::Packet& packet,
193 internal::ChannelBase& channel,
194 IntrusiveList<internal::Call>::iterator call)
195 const PW_UNLOCK_FUNCTION(internal::rpc_lock());
196
197 void HandleClientStreamPacket(const internal::Packet& packet,
198 internal::ChannelBase& channel,
199 IntrusiveList<internal::Call>::iterator call)
200 const PW_UNLOCK_FUNCTION(internal::rpc_lock());
201
202 template <typename... OtherServices>
203 void UnregisterServiceLocked(Service& service, OtherServices&... services)
204 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock()) {
205 services_.remove(service);
206 UnregisterServiceLocked(services...);
207 AbortCallsForService(service);
208 }
209
210 void UnregisterServiceLocked() {} // Base case; nothing left to do.
211
212 Status ProcessPacket(internal::Packet packet)
213 PW_LOCKS_EXCLUDED(internal::rpc_lock());
214
215 // Remove these internal::Endpoint functions from the public interface.
216 using Endpoint::active_call_count;
217 using Endpoint::ClaimLocked;
218 using Endpoint::CleanUpCalls;
219 using Endpoint::GetInternalChannel;
220
221 IntrusiveList<Service> services_ PW_GUARDED_BY(internal::rpc_lock());
222};
223
225
226} // namespace pw::rpc
Definition: status.h:109
Definition: intrusive_list.h:88
Definition: server.h:36
Definition: service.h:36
Definition: channel.h:161
Definition: span_impl.h:235
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146
#define PW_UNLOCK_FUNCTION(...)
Definition: lock_annotations.h:247
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:176