C/C++ API Reference
Loading...
Searching...
No Matches
channel.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 <cstdint>
17#include <limits>
18#include <type_traits>
19
20#include "pw_assert/assert.h"
21#include "pw_bytes/span.h"
22#include "pw_result/result.h"
23#include "pw_rpc/internal/config.h"
24#include "pw_rpc/internal/lock.h"
25#include "pw_rpc/internal/packet.h"
26#include "pw_span/span.h"
27#include "pw_status/status.h"
28
29namespace pw::rpc {
30namespace internal {
31namespace test {
32
33template <typename, typename, uint32_t>
34class InvocationContext; // Forward declaration for friend statement
35
36} // namespace test
37
38class ChannelList; // Forward declaration for friend statement
39
40Status OverwriteChannelId(ByteSpan rpc_packet, uint32_t channel_id_under_128);
41
42} // namespace internal
43
45
58
73template <uint32_t kNewChannelId>
75 static_assert(kNewChannelId < 128u,
76 "Channel IDs must be less than 128 to avoid needing to "
77 "re-encode the packet");
78 return internal::OverwriteChannelId(rpc_packet, kNewChannelId);
79}
80
85 uint32_t new_channel_id) {
86 PW_ASSERT(new_channel_id < 128);
87 return internal::OverwriteChannelId(rpc_packet, new_channel_id);
88}
89
102constexpr size_t MaxSafePayloadSize(
103 size_t encode_buffer_size = cfg::kEncodingBufferSizeBytes) {
104 return encode_buffer_size > internal::Packet::kMinEncodedSizeWithoutPayload
105 ? encode_buffer_size -
106 internal::Packet::kMinEncodedSizeWithoutPayload
107 : 0;
108}
109
111 public:
112 // Returned from MaximumTransmissionUnit() to indicate that this ChannelOutput
113 // imposes no limits on the MTU.
114 static constexpr size_t kUnlimited = std::numeric_limits<size_t>::max();
115
116 // Creates a channel output with the provided name. The name is used for
117 // logging only.
118 constexpr ChannelOutput(const char* name) : name_(name) {}
119
120 virtual ~ChannelOutput() = default;
121
122 constexpr const char* name() const { return name_; }
123
124 // Returns the maximum transmission unit that this ChannelOutput supports. If
125 // the ChannelOutput imposes no limit on the MTU, this function returns
126 // ChannelOutput::kUnlimited.
127 virtual size_t MaximumTransmissionUnit() { return kUnlimited; }
128
129 // Sends an encoded RPC packet. Returns OK if further packets may be sent,
130 // even if the current packet could not be sent. Returns any other status if
131 // the Channel is no longer able to send packets.
132 //
133 // The RPC system’s internal lock is held while this function is called. Avoid
134 // long-running operations, since these will delay any other users of the RPC
135 // system.
136 //
137 // !!! DANGER !!!
138 //
139 // No pw_rpc APIs may be accessed in this function! Implementations MUST NOT
140 // access any RPC endpoints (pw::rpc::Client, pw::rpc::Server) or call objects
141 // (pw::rpc::ServerReaderWriter, pw::rpc::ClientReaderWriter, etc.) inside the
142 // Send() function or any descendent calls. Doing so will result in deadlock!
143 // RPC APIs may be used by other threads, just not within Send().
144 //
145 // The buffer provided in packet must NOT be accessed outside of this
146 // function. It must be sent immediately or copied elsewhere before the
147 // function returns.
148 virtual Status Send(span<const std::byte> buffer)
149 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::rpc_lock()) = 0;
150
151 private:
152 const char* name_;
153};
154
156
157namespace internal {
158
159// Base class for rpc::Channel with internal-only public methods, which are
160// hidden in the public derived class.
162 public:
163 static constexpr uint32_t kUnassignedChannelId = 0;
164
165 // TODO: b/234876441 - Remove the Configure and set_channel_output functions.
166 // Users should call CloseChannel() / OpenChannel() to change a channel.
167 // This ensures calls are properly update and works consistently between
168 // static and dynamic channel allocation.
169
170 // Manually configures a dynamically-assignable channel with a specified ID
171 // and output. This is useful when a channel's parameters are not known until
172 // runtime. This can only be called once per channel.
173 template <typename UnusedType = void>
174 constexpr void Configure(uint32_t id, ChannelOutput& output) {
175 static_assert(
176 !cfg::kDynamicAllocationEnabled<UnusedType>,
177 "Configure() may not be used if PW_RPC_DYNAMIC_ALLOCATION is "
178 "enabled. Call CloseChannel/OpenChannel on the endpoint instead.");
179 PW_ASSERT(id_ == kUnassignedChannelId);
180 PW_ASSERT(id != kUnassignedChannelId);
181 id_ = id;
182 output_ = &output;
183 }
184
185 // Configure using an enum value channel ID.
186 template <typename T,
187 typename = std::enable_if_t<std::is_enum_v<T>>,
188 typename U = std::underlying_type_t<T>>
189 constexpr void Configure(T id, ChannelOutput& output) {
190 static_assert(
191 !cfg::kDynamicAllocationEnabled<T>,
192 "Configure() may not be used if PW_RPC_DYNAMIC_ALLOCATION is enabled. "
193 "Call CloseChannel/OpenChannel on the endpoint instead.");
194 static_assert(sizeof(U) <= sizeof(uint32_t));
195 const U kIntId = static_cast<U>(id);
196 PW_ASSERT(kIntId > 0);
197 return Configure<T>(static_cast<uint32_t>(kIntId), output);
198 }
199
200 // Reconfigures a channel with a new output. Depending on the output's
201 // implementatation, there might be unintended behavior if the output is in
202 // use.
203 template <typename UnusedType = void>
204 constexpr void set_channel_output(ChannelOutput& output) {
205 static_assert(
206 !cfg::kDynamicAllocationEnabled<UnusedType>,
207 "set_channel_output() may not be used if PW_RPC_DYNAMIC_ALLOCATION is "
208 "enabled. Call CloseChannel/OpenChannel on the endpoint instead.");
209 PW_ASSERT(id_ != kUnassignedChannelId);
210 output_ = &output;
211 }
212
213 constexpr uint32_t id() const { return id_; }
214 constexpr bool assigned() const { return id_ != kUnassignedChannelId; }
215
216 //
217 // Internal functions made private in the public Channel class.
218 //
219
220 // Invokes ChannelOutput::Send and returns its status. Any non-OK status
221 // indicates that the Channel is permanently closed.
222 Status Send(const Packet& packet) PW_EXCLUSIVE_LOCKS_REQUIRED(rpc_lock());
223
224 constexpr void Close() {
225 PW_ASSERT(id_ != kUnassignedChannelId);
226 id_ = kUnassignedChannelId;
227 output_ = nullptr;
228 }
229
230 // Returns the maximum payload size for this channel, factoring in the
231 // ChannelOutput's MTU and the RPC system's `pw::rpc::MaxSafePayloadSize()`.
232 size_t MaxWriteSizeBytes() const;
233
234 protected:
235 constexpr ChannelBase(uint32_t id, ChannelOutput* output)
236 : id_(id), output_(output) {}
237
238 private:
239 uint32_t id_;
240 ChannelOutput* output_;
241};
242
243} // namespace internal
244
245// Associates an ID with an interface for sending packets.
247 public:
248 // Creates a channel with a static ID. The channel's output can also be
249 // static, or it can set to null to allow dynamically opening connections
250 // through the channel.
251 template <uint32_t kId>
252 constexpr static Channel Create(ChannelOutput* output) {
253 static_assert(kId != kUnassignedChannelId, "Channel ID cannot be 0");
254 return Channel(kId, output);
255 }
256
257 // Creates a channel with a static ID from an enum value.
258 template <auto kId,
259 typename T = decltype(kId),
260 typename = std::enable_if_t<std::is_enum_v<T>>,
261 typename U = std::underlying_type_t<T>>
262 constexpr static Channel Create(ChannelOutput* output) {
263 constexpr U kIntId = static_cast<U>(kId);
264 static_assert(kIntId >= 0, "Channel ID cannot be negative");
265 static_assert(kIntId <= std::numeric_limits<uint32_t>::max(),
266 "Channel ID must fit in a uint32");
267 return Create<static_cast<uint32_t>(kIntId)>(output);
268 }
269
270 // Creates a dynamically assignable channel without a set ID or output.
271 constexpr Channel() : internal::ChannelBase(kUnassignedChannelId, nullptr) {}
272
273 private:
274 template <typename, typename, uint32_t>
276 friend class internal::ChannelList;
277
278 constexpr Channel(uint32_t id, ChannelOutput* output)
279 : internal::ChannelBase(id, output) {
280 PW_ASSERT(id != kUnassignedChannelId);
281 }
282
283 private:
284 // Hide internal-only methods defined in the internal::ChannelBase.
285 using internal::ChannelBase::Close;
286 using internal::ChannelBase::MaxWriteSizeBytes;
287 using internal::ChannelBase::Send;
288};
289
290} // namespace pw::rpc
Definition: poll.h:25
Definition: status.h:109
Definition: channel.h:246
Definition: channel.h:110
Definition: channel.h:161
constexpr size_t MaxSafePayloadSize(size_t encode_buffer_size=cfg::kEncodingBufferSizeBytes)
Definition: channel.h:102
Status ChangeEncodedChannelId(ByteSpan rpc_packet)
Definition: channel.h:74
Result< uint32_t > ExtractChannelId(ConstByteSpan packet)
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146