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 #include <span> 19 20 #include "pw_bytes/span.h" 21 #include "pw_protobuf/serialized_size.h" 22 #include "pw_rpc/internal/packet.pwpb.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 static constexpr size_t kMinEncodedSizeWithoutPayload = 32 protobuf::SizeOfFieldEnum(RpcPacket::Fields::TYPE, 7) + 33 protobuf::SizeOfFieldUint32(RpcPacket::Fields::CHANNEL_ID) + 34 protobuf::SizeOfFieldUint32(RpcPacket::Fields::SERVICE_ID) + 35 protobuf::SizeOfFieldUint32(RpcPacket::Fields::METHOD_ID) + 36 protobuf::SizeOfDelimitedFieldWithoutValue(RpcPacket::Fields::PAYLOAD) + 37 protobuf::SizeOfFieldUint32(RpcPacket::Fields::STATUS, 38 Status::Unauthenticated().code()) + 39 protobuf::SizeOfFieldUint32(RpcPacket::Fields::CALL_ID); 40 ; 41 42 // Parses a packet from a protobuf message. Missing or malformed fields take 43 // their default values. 44 static Result<Packet> FromBuffer(ConstByteSpan data); 45 46 // Creates an RPC packet with the channel, service, and method ID of the 47 // provided packet. 48 static constexpr Packet Response(const Packet& request, 49 Status status = OkStatus()) { 50 return Packet(PacketType::RESPONSE, 51 request.channel_id(), 52 request.service_id(), 53 request.method_id(), 54 request.call_id(), 55 {}, 56 status); 57 } 58 59 // Creates a SERVER_ERROR packet with the channel, service, and method ID of 60 // the provided packet. ServerError(const Packet & packet,Status status)61 static constexpr Packet ServerError(const Packet& packet, Status status) { 62 return Packet(PacketType::SERVER_ERROR, 63 packet.channel_id(), 64 packet.service_id(), 65 packet.method_id(), 66 packet.call_id(), 67 {}, 68 status); 69 } 70 71 // Creates a CLIENT_ERROR packet with the channel, service, and method ID of 72 // the provided packet. ClientError(const Packet & packet,Status status)73 static constexpr Packet ClientError(const Packet& packet, Status status) { 74 return Packet(PacketType::CLIENT_ERROR, 75 packet.channel_id(), 76 packet.service_id(), 77 packet.method_id(), 78 packet.call_id(), 79 {}, 80 status); 81 } 82 83 // Creates an empty packet. Packet()84 constexpr Packet() 85 : Packet(PacketType{}, kUnassignedId, kUnassignedId, kUnassignedId) {} 86 87 constexpr Packet(PacketType type, 88 uint32_t channel_id, 89 uint32_t service_id, 90 uint32_t method_id, 91 uint32_t call_id = kUnassignedId, 92 ConstByteSpan payload = {}, 93 Status status = OkStatus()) type_(type)94 : type_(type), 95 channel_id_(channel_id), 96 service_id_(service_id), 97 method_id_(method_id), 98 call_id_(call_id), 99 payload_(payload), 100 status_(status) {} 101 102 // Encodes the packet into its wire format. Returns the encoded size. 103 Result<ConstByteSpan> Encode(ByteSpan buffer) const; 104 105 // Determines the space required to encode the packet proto fields for a 106 // response, excluding the payload. This may be used to split the buffer into 107 // reserved space and available space for the payload. 108 // 109 // This method allocates two bytes for the status. Status code 0 (OK) is not 110 // encoded since 0 is the default value. 111 size_t MinEncodedSizeBytes() const; 112 113 enum Destination : bool { kServer, kClient }; 114 destination()115 constexpr Destination destination() const { 116 return static_cast<int>(type_) % 2 == 0 ? kServer : kClient; 117 } 118 type()119 constexpr PacketType type() const { return type_; } channel_id()120 constexpr uint32_t channel_id() const { return channel_id_; } service_id()121 constexpr uint32_t service_id() const { return service_id_; } method_id()122 constexpr uint32_t method_id() const { return method_id_; } call_id()123 constexpr uint32_t call_id() const { return call_id_; } payload()124 constexpr const ConstByteSpan& payload() const { return payload_; } status()125 constexpr const Status& status() const { return status_; } 126 set_type(PacketType type)127 constexpr void set_type(PacketType type) { type_ = type; } set_channel_id(uint32_t channel_id)128 constexpr void set_channel_id(uint32_t channel_id) { 129 channel_id_ = channel_id; 130 } set_service_id(uint32_t service_id)131 constexpr void set_service_id(uint32_t service_id) { 132 service_id_ = service_id; 133 } set_method_id(uint32_t method_id)134 constexpr void set_method_id(uint32_t method_id) { method_id_ = method_id; } set_call_id(uint32_t call_id)135 constexpr void set_call_id(uint32_t call_id) { call_id_ = call_id; } set_payload(ConstByteSpan payload)136 constexpr void set_payload(ConstByteSpan payload) { payload_ = payload; } set_status(Status status)137 constexpr void set_status(Status status) { status_ = status; } 138 139 private: 140 PacketType type_; 141 uint32_t channel_id_; 142 uint32_t service_id_; 143 uint32_t method_id_; 144 uint32_t call_id_; 145 ConstByteSpan payload_; 146 Status status_; 147 }; 148 149 } // namespace pw::rpc::internal 150