xref: /aosp_15_r20/external/pigweed/pw_rpc/public/pw_rpc/internal/packet.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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 <cstdint>
18 
19 #include "pw_bytes/span.h"
20 #include "pw_protobuf/serialized_size.h"
21 #include "pw_rpc/internal/packet.pwpb.h"
22 #include "pw_span/span.h"
23 #include "pw_status/status_with_size.h"
24 
25 namespace pw::rpc::internal {
26 
27 class Packet {
28  public:
29   static constexpr uint32_t kUnassignedId = 0;
30 
31   // TODO: b/236156534 - This can use the pwpb generated
32   // pw::rpc::internal::pwpb::RpcPacket::kMaxEncodedSizeBytes once the max value
33   // of enums is properly accounted for and when `status` is changed from a
34   // uint32 to a StatusCode.
35   static constexpr size_t kMinEncodedSizeWithoutPayload =
36       protobuf::SizeOfFieldEnum(pwpb::RpcPacket::Fields::kType, 7) +
37       protobuf::SizeOfFieldUint32(pwpb::RpcPacket::Fields::kChannelId) +
38       protobuf::SizeOfFieldFixed32(pwpb::RpcPacket::Fields::kServiceId) +
39       protobuf::SizeOfFieldFixed32(pwpb::RpcPacket::Fields::kMethodId) +
40       protobuf::SizeOfDelimitedFieldWithoutValue(
41           pwpb::RpcPacket::Fields::kPayload) +
42       protobuf::SizeOfFieldUint32(pwpb::RpcPacket::Fields::kStatus,
43                                   Status::Unauthenticated().code()) +
44       protobuf::SizeOfFieldUint32(pwpb::RpcPacket::Fields::kCallId);
45 
46   // Parses a packet from a protobuf message. Missing or malformed fields take
47   // their default values.
48   static Result<Packet> FromBuffer(ConstByteSpan data);
49 
50   // Creates an RPC packet with the channel, service, and method ID of the
51   // provided packet.
52   static constexpr Packet Response(const Packet& request,
53                                    Status status = OkStatus()) {
54     return Packet(pwpb::PacketType::RESPONSE,
55                   request.channel_id(),
56                   request.service_id(),
57                   request.method_id(),
58                   request.call_id(),
59                   {},
60                   status);
61   }
62 
63   // Creates a SERVER_ERROR packet with the channel, service, and method ID of
64   // the provided packet.
ServerError(const Packet & packet,Status status)65   static constexpr Packet ServerError(const Packet& packet, Status status) {
66     return Packet(pwpb::PacketType::SERVER_ERROR,
67                   packet.channel_id(),
68                   packet.service_id(),
69                   packet.method_id(),
70                   packet.call_id(),
71                   {},
72                   status);
73   }
74 
75   // Creates a CLIENT_ERROR packet with the channel, service, and method ID of
76   // the provided packet.
ClientError(const Packet & packet,Status status)77   static constexpr Packet ClientError(const Packet& packet, Status status) {
78     return Packet(pwpb::PacketType::CLIENT_ERROR,
79                   packet.channel_id(),
80                   packet.service_id(),
81                   packet.method_id(),
82                   packet.call_id(),
83                   {},
84                   status);
85   }
86 
87   // Creates an empty packet.
Packet()88   constexpr Packet()
89       : Packet(pwpb::PacketType{},
90                kUnassignedId,
91                kUnassignedId,
92                kUnassignedId,
93                kUnassignedId) {}
94 
95   constexpr Packet(pwpb::PacketType type,
96                    uint32_t channel_id,
97                    uint32_t service_id,
98                    uint32_t method_id,
99                    uint32_t call_id,
100                    ConstByteSpan payload = {},
101                    Status status = OkStatus())
type_(type)102       : type_(type),
103         channel_id_(channel_id),
104         service_id_(service_id),
105         method_id_(method_id),
106         call_id_(call_id),
107         payload_(payload),
108         status_(status) {}
109 
110   // Encodes the packet into its wire format. Returns the encoded size.
111   Result<ConstByteSpan> Encode(ByteSpan buffer) const;
112 
113   // Determines the space required to encode the packet proto fields for a
114   // response, excluding the payload. This may be used to split the buffer into
115   // reserved space and available space for the payload.
116   //
117   // This method allocates two bytes for the status. Status code 0 (OK) is not
118   // encoded since 0 is the default value.
119   size_t MinEncodedSizeBytes() const;
120 
121   enum Destination : bool { kServer, kClient };
122 
destination()123   constexpr Destination destination() const {
124     return static_cast<int>(type_) % 2 == 0 ? kServer : kClient;
125   }
126 
type()127   constexpr pwpb::PacketType type() const { return type_; }
channel_id()128   constexpr uint32_t channel_id() const { return channel_id_; }
service_id()129   constexpr uint32_t service_id() const { return service_id_; }
method_id()130   constexpr uint32_t method_id() const { return method_id_; }
call_id()131   constexpr uint32_t call_id() const { return call_id_; }
payload()132   constexpr const ConstByteSpan& payload() const { return payload_; }
status()133   constexpr const Status& status() const { return status_; }
134 
set_type(pwpb::PacketType type)135   constexpr void set_type(pwpb::PacketType type) { type_ = type; }
set_channel_id(uint32_t channel_id)136   constexpr void set_channel_id(uint32_t channel_id) {
137     channel_id_ = channel_id;
138   }
set_service_id(uint32_t service_id)139   constexpr void set_service_id(uint32_t service_id) {
140     service_id_ = service_id;
141   }
set_method_id(uint32_t method_id)142   constexpr void set_method_id(uint32_t method_id) { method_id_ = method_id; }
set_call_id(uint32_t call_id)143   constexpr void set_call_id(uint32_t call_id) { call_id_ = call_id; }
set_payload(ConstByteSpan payload)144   constexpr void set_payload(ConstByteSpan payload) { payload_ = payload; }
set_status(Status status)145   constexpr void set_status(Status status) { status_ = status; }
146 
147   // Logs detailed info about this packet at INFO level. NOT for production use!
148   void DebugLog() const;
149 
150  private:
151   pwpb::PacketType type_;
152   uint32_t channel_id_;
153   uint32_t service_id_;
154   uint32_t method_id_;
155   uint32_t call_id_;
156   ConstByteSpan payload_;
157   Status status_;
158 };
159 
160 }  // namespace pw::rpc::internal
161