• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
90             pwpb::PacketType{}, kUnassignedId, kUnassignedId, kUnassignedId) {}
91 
92   constexpr Packet(pwpb::PacketType type,
93                    uint32_t channel_id,
94                    uint32_t service_id,
95                    uint32_t method_id,
96                    uint32_t call_id = kUnassignedId,
97                    ConstByteSpan payload = {},
98                    Status status = OkStatus())
type_(type)99       : type_(type),
100         channel_id_(channel_id),
101         service_id_(service_id),
102         method_id_(method_id),
103         call_id_(call_id),
104         payload_(payload),
105         status_(status) {}
106 
107   // Encodes the packet into its wire format. Returns the encoded size.
108   Result<ConstByteSpan> Encode(ByteSpan buffer) const;
109 
110   // Determines the space required to encode the packet proto fields for a
111   // response, excluding the payload. This may be used to split the buffer into
112   // reserved space and available space for the payload.
113   //
114   // This method allocates two bytes for the status. Status code 0 (OK) is not
115   // encoded since 0 is the default value.
116   size_t MinEncodedSizeBytes() const;
117 
118   enum Destination : bool { kServer, kClient };
119 
destination()120   constexpr Destination destination() const {
121     return static_cast<int>(type_) % 2 == 0 ? kServer : kClient;
122   }
123 
type()124   constexpr pwpb::PacketType type() const { return type_; }
channel_id()125   constexpr uint32_t channel_id() const { return channel_id_; }
service_id()126   constexpr uint32_t service_id() const { return service_id_; }
method_id()127   constexpr uint32_t method_id() const { return method_id_; }
call_id()128   constexpr uint32_t call_id() const { return call_id_; }
payload()129   constexpr const ConstByteSpan& payload() const { return payload_; }
status()130   constexpr const Status& status() const { return status_; }
131 
set_type(pwpb::PacketType type)132   constexpr void set_type(pwpb::PacketType type) { type_ = type; }
set_channel_id(uint32_t channel_id)133   constexpr void set_channel_id(uint32_t channel_id) {
134     channel_id_ = channel_id;
135   }
set_service_id(uint32_t service_id)136   constexpr void set_service_id(uint32_t service_id) {
137     service_id_ = service_id;
138   }
set_method_id(uint32_t method_id)139   constexpr void set_method_id(uint32_t method_id) { method_id_ = method_id; }
set_call_id(uint32_t call_id)140   constexpr void set_call_id(uint32_t call_id) { call_id_ = call_id; }
set_payload(ConstByteSpan payload)141   constexpr void set_payload(ConstByteSpan payload) { payload_ = payload; }
set_status(Status status)142   constexpr void set_status(Status status) { status_ = status; }
143 
144  private:
145   pwpb::PacketType type_;
146   uint32_t channel_id_;
147   uint32_t service_id_;
148   uint32_t method_id_;
149   uint32_t call_id_;
150   ConstByteSpan payload_;
151   Status status_;
152 };
153 
154 }  // namespace pw::rpc::internal
155