libe3 0.2.5
C++ library for E3AP RAN vendor integration
Loading...
Searching...
No Matches
protobuf_encoder.cpp
Go to the documentation of this file.
1/**
2 * @file protobuf_encoder.cpp
3 * @brief Protocol Buffers encoder for E3AP PDUs
4 *
5 * SPDX-FileCopyrightText: Copyright (c) 2026 Northeastern University
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
10
11#include "e3ap-1.0.0.pb.h"
12
13#include <string>
14#include <vector>
15
16namespace libe3 {
17
18namespace pb = e3ap::v1;
19
20namespace {
21
22pb::ResponseCode to_pb_response_code(ResponseCode rc) {
23 return rc == ResponseCode::POSITIVE ? pb::RESPONSE_CODE_POSITIVE
24 : pb::RESPONSE_CODE_NEGATIVE;
25}
26
27ResponseCode from_pb_response_code(pb::ResponseCode rc) {
28 return rc == pb::RESPONSE_CODE_NEGATIVE ? ResponseCode::NEGATIVE
29 : ResponseCode::POSITIVE;
30}
31
32std::vector<uint8_t> to_bytes(const std::string& s) {
33 return std::vector<uint8_t>(s.begin(), s.end());
34}
35
36} // namespace
37
38bool ProtobufE3Encoder::pdu_to_proto(const Pdu& pdu, pb::E3Pdu& out) const {
39 out.set_id(pdu.message_id);
40 out.set_timestamp(pdu.timestamp);
41
42 switch (pdu.type) {
44 const auto* s = pdu.get_if<SetupRequest>();
45 if (!s) return false;
46 auto* m = out.mutable_setup_request();
47 m->set_e3ap_protocol_version(s->e3ap_protocol_version);
48 m->set_dapp_name(s->dapp_name);
49 m->set_dapp_version(s->dapp_version);
50 m->set_vendor(s->vendor);
51 return true;
52 }
54 const auto* s = pdu.get_if<SetupResponse>();
55 if (!s) return false;
56 auto* m = out.mutable_setup_response();
57 m->set_request_id(s->request_id);
58 m->set_response_code(to_pb_response_code(s->response_code));
59 if (s->e3ap_protocol_version) m->set_e3ap_protocol_version(*s->e3ap_protocol_version);
60 if (s->dapp_identifier) m->set_dapp_identifier(*s->dapp_identifier);
61 m->set_ran_identifier(s->ran_identifier);
62 for (const auto& rf : s->ran_function_list) {
63 auto* pf = m->add_ran_function_list();
64 pf->set_ran_function_identifier(rf.ran_function_identifier);
65 for (auto t : rf.telemetry_identifier_list) pf->add_telemetry_identifier_list(t);
66 for (auto c : rf.control_identifier_list) pf->add_control_identifier_list(c);
67 pf->set_ran_function_data(rf.ran_function_data.data(), rf.ran_function_data.size());
68 }
69 return true;
70 }
72 const auto* s = pdu.get_if<SubscriptionRequest>();
73 if (!s) return false;
74 auto* m = out.mutable_subscription_request();
75 m->set_dapp_identifier(s->dapp_identifier);
76 m->set_ran_function_identifier(s->ran_function_identifier);
77 for (auto t : s->telemetry_identifier_list) m->add_telemetry_identifier_list(t);
78 for (auto c : s->control_identifier_list) m->add_control_identifier_list(c);
79 if (s->subscription_time) m->set_subscription_time(*s->subscription_time);
80 if (s->periodicity) m->set_periodicity(*s->periodicity);
81 return true;
82 }
84 const auto* s = pdu.get_if<SubscriptionDelete>();
85 if (!s) return false;
86 auto* m = out.mutable_subscription_delete();
87 m->set_dapp_identifier(s->dapp_identifier);
88 m->set_subscription_id(s->subscription_id);
89 return true;
90 }
92 const auto* s = pdu.get_if<SubscriptionResponse>();
93 if (!s) return false;
94 auto* m = out.mutable_subscription_response();
95 m->set_request_id(s->request_id);
96 m->set_dapp_identifier(s->dapp_identifier);
97 m->set_response_code(to_pb_response_code(s->response_code));
98 if (s->subscription_id) m->set_subscription_id(*s->subscription_id);
99 return true;
100 }
102 const auto* s = pdu.get_if<IndicationMessage>();
103 if (!s) return false;
104 auto* m = out.mutable_indication_message();
105 m->set_dapp_identifier(s->dapp_identifier);
106 m->set_ran_function_identifier(s->ran_function_identifier);
107 m->set_protocol_data(s->protocol_data.data(), s->protocol_data.size());
108 return true;
109 }
111 const auto* s = pdu.get_if<DAppControlAction>();
112 if (!s) return false;
113 auto* m = out.mutable_dapp_control_action();
114 m->set_dapp_identifier(s->dapp_identifier);
115 m->set_ran_function_identifier(s->ran_function_identifier);
116 m->set_control_identifier(s->control_identifier);
117 m->set_sequence_id(s->sequence_id);
118 m->set_action_data(s->action_data.data(), s->action_data.size());
119 return true;
120 }
122 const auto* s = pdu.get_if<DAppReport>();
123 if (!s) return false;
124 auto* m = out.mutable_dapp_report();
125 m->set_dapp_identifier(s->dapp_identifier);
126 m->set_ran_function_identifier(s->ran_function_identifier);
127 m->set_sequence_id(s->sequence_id);
128 m->set_report_data(s->report_data.data(), s->report_data.size());
129 return true;
130 }
132 const auto* s = pdu.get_if<XAppControlAction>();
133 if (!s) return false;
134 auto* m = out.mutable_xapp_control_action();
135 m->set_dapp_identifier(s->dapp_identifier);
136 m->set_ran_function_identifier(s->ran_function_identifier);
137 m->set_sequence_id(s->sequence_id);
138 m->set_xapp_control_data(s->xapp_control_data.data(), s->xapp_control_data.size());
139 return true;
140 }
142 const auto* s = pdu.get_if<ReleaseMessage>();
143 if (!s) return false;
144 auto* m = out.mutable_release_message();
145 m->set_dapp_identifier(s->dapp_identifier);
146 return true;
147 }
149 const auto* s = pdu.get_if<MessageAck>();
150 if (!s) return false;
151 auto* m = out.mutable_message_ack();
152 m->set_request_id(s->request_id);
153 m->set_response_code(to_pb_response_code(s->response_code));
154 return true;
155 }
156 }
157 return false;
158}
159
160Pdu ProtobufE3Encoder::proto_to_pdu(const pb::E3Pdu& proto) const {
161 Pdu pdu;
162 pdu.message_id = proto.id();
163 pdu.timestamp = proto.timestamp();
164
165 switch (proto.msg_case()) {
166 case pb::E3Pdu::kSetupRequest: {
167 const auto& m = proto.setup_request();
168 SetupRequest s;
169 s.e3ap_protocol_version = m.e3ap_protocol_version();
170 s.dapp_name = m.dapp_name();
171 s.dapp_version = m.dapp_version();
172 s.vendor = m.vendor();
173 pdu.type = PduType::SETUP_REQUEST;
174 pdu.choice = std::move(s);
175 break;
176 }
177 case pb::E3Pdu::kSetupResponse: {
178 const auto& m = proto.setup_response();
179 SetupResponse s;
180 s.request_id = m.request_id();
181 s.response_code = from_pb_response_code(m.response_code());
182 if (m.has_e3ap_protocol_version()) s.e3ap_protocol_version = m.e3ap_protocol_version();
183 if (m.has_dapp_identifier()) s.dapp_identifier = m.dapp_identifier();
184 s.ran_identifier = m.ran_identifier();
185 for (int i = 0; i < m.ran_function_list_size(); ++i) {
186 const auto& pf = m.ran_function_list(i);
187 RanFunctionDef rf;
188 rf.ran_function_identifier = pf.ran_function_identifier();
189 for (int j = 0; j < pf.telemetry_identifier_list_size(); ++j)
190 rf.telemetry_identifier_list.push_back(pf.telemetry_identifier_list(j));
191 for (int j = 0; j < pf.control_identifier_list_size(); ++j)
192 rf.control_identifier_list.push_back(pf.control_identifier_list(j));
193 rf.ran_function_data = to_bytes(pf.ran_function_data());
194 s.ran_function_list.push_back(std::move(rf));
195 }
196 pdu.type = PduType::SETUP_RESPONSE;
197 pdu.choice = std::move(s);
198 break;
199 }
200 case pb::E3Pdu::kSubscriptionRequest: {
201 const auto& m = proto.subscription_request();
202 SubscriptionRequest s;
203 s.dapp_identifier = m.dapp_identifier();
204 s.ran_function_identifier = m.ran_function_identifier();
205 for (int j = 0; j < m.telemetry_identifier_list_size(); ++j)
206 s.telemetry_identifier_list.push_back(m.telemetry_identifier_list(j));
207 for (int j = 0; j < m.control_identifier_list_size(); ++j)
208 s.control_identifier_list.push_back(m.control_identifier_list(j));
209 if (m.has_subscription_time()) s.subscription_time = m.subscription_time();
210 if (m.has_periodicity()) s.periodicity = m.periodicity();
212 pdu.choice = std::move(s);
213 break;
214 }
215 case pb::E3Pdu::kSubscriptionDelete: {
216 const auto& m = proto.subscription_delete();
217 SubscriptionDelete s;
218 s.dapp_identifier = m.dapp_identifier();
219 s.subscription_id = m.subscription_id();
221 pdu.choice = std::move(s);
222 break;
223 }
224 case pb::E3Pdu::kSubscriptionResponse: {
225 const auto& m = proto.subscription_response();
226 SubscriptionResponse s;
227 s.request_id = m.request_id();
228 s.dapp_identifier = m.dapp_identifier();
229 s.response_code = from_pb_response_code(m.response_code());
230 if (m.has_subscription_id()) s.subscription_id = m.subscription_id();
232 pdu.choice = std::move(s);
233 break;
234 }
235 case pb::E3Pdu::kIndicationMessage: {
236 const auto& m = proto.indication_message();
237 IndicationMessage s;
238 s.dapp_identifier = m.dapp_identifier();
239 s.ran_function_identifier = m.ran_function_identifier();
240 s.protocol_data = to_bytes(m.protocol_data());
242 pdu.choice = std::move(s);
243 break;
244 }
245 case pb::E3Pdu::kDappControlAction: {
246 const auto& m = proto.dapp_control_action();
247 DAppControlAction s;
248 s.dapp_identifier = m.dapp_identifier();
249 s.ran_function_identifier = m.ran_function_identifier();
250 s.control_identifier = m.control_identifier();
251 s.sequence_id = m.sequence_id();
252 s.action_data = to_bytes(m.action_data());
254 pdu.choice = std::move(s);
255 break;
256 }
257 case pb::E3Pdu::kDappReport: {
258 const auto& m = proto.dapp_report();
259 DAppReport s;
260 s.dapp_identifier = m.dapp_identifier();
261 s.ran_function_identifier = m.ran_function_identifier();
262 s.sequence_id = m.sequence_id();
263 s.report_data = to_bytes(m.report_data());
264 pdu.type = PduType::DAPP_REPORT;
265 pdu.choice = std::move(s);
266 break;
267 }
268 case pb::E3Pdu::kXappControlAction: {
269 const auto& m = proto.xapp_control_action();
270 XAppControlAction s;
271 s.dapp_identifier = m.dapp_identifier();
272 s.ran_function_identifier = m.ran_function_identifier();
273 s.sequence_id = m.sequence_id();
274 s.xapp_control_data = to_bytes(m.xapp_control_data());
276 pdu.choice = std::move(s);
277 break;
278 }
279 case pb::E3Pdu::kReleaseMessage: {
280 const auto& m = proto.release_message();
281 ReleaseMessage s;
282 s.dapp_identifier = m.dapp_identifier();
283 pdu.type = PduType::RELEASE_MESSAGE;
284 pdu.choice = std::move(s);
285 break;
286 }
287 case pb::E3Pdu::kMessageAck: {
288 const auto& m = proto.message_ack();
289 MessageAck s;
290 s.request_id = m.request_id();
291 s.response_code = from_pb_response_code(m.response_code());
292 pdu.type = PduType::MESSAGE_ACK;
293 pdu.choice = std::move(s);
294 break;
295 }
296 case pb::E3Pdu::MSG_NOT_SET:
297 break;
298 }
299 return pdu;
300}
301
303 pb::E3Pdu proto;
304 if (!pdu_to_proto(pdu, proto)) {
305 return tl::unexpected(ErrorCode::ENCODE_FAILED);
306 }
307 std::string serialized;
308 if (!proto.SerializeToString(&serialized)) {
309 return tl::unexpected(ErrorCode::ENCODE_FAILED);
310 }
311 return EncodedMessage{std::vector<uint8_t>(serialized.begin(), serialized.end()),
313}
314
316 return decode(encoded.buffer.data(), encoded.buffer.size());
317}
318
319EncodeResult<Pdu> ProtobufE3Encoder::decode(const uint8_t* data, size_t size) {
320 if (data == nullptr && size != 0) {
321 return tl::unexpected(ErrorCode::DECODE_FAILED);
322 }
323 pb::E3Pdu proto;
324 if (!proto.ParseFromArray(data, static_cast<int>(size))) {
325 return tl::unexpected(ErrorCode::DECODE_FAILED);
326 }
327 if (proto.msg_case() == pb::E3Pdu::MSG_NOT_SET) {
328 return tl::unexpected(ErrorCode::DECODE_FAILED);
329 }
330 return proto_to_pdu(proto);
331}
332
333} // namespace libe3
EncodeResult< Pdu > decode(const EncodedMessage &encoded) override
Decode bytes to a PDU.
EncodeResult< EncodedMessage > encode(const Pdu &pdu) override
Encode a PDU to bytes.
ResponseCode
E3AP response codes.
Definition types.hpp:101
@ SUBSCRIPTION_DELETE
Definition types.hpp:113
@ SUBSCRIPTION_RESPONSE
Definition types.hpp:114
@ SUBSCRIPTION_REQUEST
Definition types.hpp:112
@ XAPP_CONTROL_ACTION
Definition types.hpp:118
@ DAPP_CONTROL_ACTION
Definition types.hpp:116
@ PROTOBUF
Protocol Buffers encoding.
Definition types.hpp:54
tl::expected< T, ErrorCode > EncodeResult
Result type for encoding/decoding operations.
Protocol Buffers encoder for E3AP PDUs.
Encoded message wrapper.
Definition types.hpp:175
std::vector< uint8_t > buffer
Encoded data buffer.
Definition types.hpp:176
Generic E3AP PDU structure.
Definition types.hpp:345
uint32_t message_id
Unique message identifier.
Definition types.hpp:348