libe3 0.2.5
C++ library for E3AP RAN vendor integration
Loading...
Searching...
No Matches
e3_agent.hpp
Go to the documentation of this file.
1/**
2 * @file e3_agent.hpp
3 * @brief E3Agent - Main façade class for RAN vendors
4 *
5 * This is the ONLY class RAN vendors should interact with. It provides
6 * a clean, stable public API while hiding all internal implementation
7 * details (connectors, encoders, threads, state machines).
8 *
9 * SPDX-FileCopyrightText: Copyright (c) 2026 Northeastern University
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13#ifndef LIBE3_E3_AGENT_HPP
14#define LIBE3_E3_AGENT_HPP
15
16#include "types.hpp"
17#include "sm_interface.hpp"
18#include <memory>
19#include <functional>
20#include <vector>
21#include <optional>
22#include <chrono>
23
24namespace libe3 {
25
26// Forward declaration - implementation hidden from users
27class E3Interface;
28
29/** Callback for incoming dApp reports (dApp → RAN). Set before start() to handle reports. */
30using DAppReportHandler = std::function<void(const DAppReport&)>;
31
32/** Callback when dApp status changes (connect, disconnect, subscribe, unsubscribe). */
33using DAppStatusChangedHandler = std::function<void()>;
34
35// dApp-side handlers (used when role==DAPP).
36using SetupResponseHandler = std::function<void(const SetupResponse&)>;
37using SubscriptionResponseHandler = std::function<void(const SubscriptionResponse&)>;
38using IndicationHandler = std::function<void(const IndicationMessage&)>;
39using XAppControlHandler = std::function<void(const XAppControlAction&)>;
40using MessageAckHandler = std::function<void(const MessageAck&)>;
41
42/**
43 * @brief E3Agent - Main façade for RAN vendor integration
44 *
45 * This class is the primary entry point for integrating E3AP functionality
46 * into a RAN function (DU, CU-CP, CU-UP). It provides:
47 *
48 * - Simple lifecycle management (init, start, stop, destroy)
49 * - Service Model registration
50 * - Automatic routing of control actions to the correct Service Model
51 * - Thread-safe operation
52 *
53 * **Usage Example:**
54 * ```cpp
55 * // Create agent with configuration
56 * libe3::E3Config config;
57 * config.link_layer = libe3::E3LinkLayer::ZMQ;
58 * config.transport_layer = libe3::E3TransportLayer::IPC;
59 * config.encoding = libe3::EncodingFormat::JSON;
60 * // Set custom ports if needed
61 * config.setup_port = 9990;
62 * config.subscriber_port = 9999;
63 * config.publisher_port = 9991;
64
65 * libe3::E3Agent agent(config);
66
67 * // Register Service Models
68 * agent.register_sm(std::make_unique<MySpectrumSM>());
69
70 * // Start the agent
71 * if (agent.start() != libe3::ErrorCode::SUCCESS) {
72 * // Handle error
73 * }
74
75 * // ... agent runs, handling dApp connections and messages ...
76
77 * // Shutdown
78 * agent.stop();
79 * ```
80 *
81 * **Thread Safety:**
82 * All public methods are thread-safe. The agent manages its own internal
83 * threads for protocol handling.
84 */
85class E3Agent {
86public:
87 /**
88 * @brief Construct an E3Agent with configuration
89 *
90 * @param config Agent configuration
91 */
92 explicit E3Agent(E3Config config = E3Config{});
93
94 /**
95 * @brief Destructor - ensures clean shutdown
96 */
97 ~E3Agent();
98
99 // Non-copyable, movable
100 E3Agent(const E3Agent&) = delete;
101 E3Agent& operator=(const E3Agent&) = delete;
102 E3Agent(E3Agent&&) noexcept;
103 E3Agent& operator=(E3Agent&&) noexcept;
104
105 // =========================================================================
106 // Lifecycle Management
107 // =========================================================================
108
109 /**
110 * @brief Initialize the agent
111 *
112 * Initializes internal components but does not start processing.
113 * Must be called before start().
114 *
115 * @return ErrorCode::SUCCESS on success
116 * @return ErrorCode::ALREADY_INITIALIZED if already initialized
117 */
118 ErrorCode init();
119
120 /**
121 * @brief Start the agent
122 *
123 * Starts the internal processing threads and begins accepting
124 * dApp connections. If not already initialized, calls init() first.
125 *
126 * @return ErrorCode::SUCCESS on success
127 */
129
130 /**
131 * @brief Stop the agent
132 *
133 * Stops all processing threads and closes connections.
134 * The agent can be restarted with start().
135 */
136 void stop();
137
138 /**
139 * @brief Get current agent state
140 */
141 AgentState state() const noexcept;
142
143 /**
144 * @brief Check if agent is running
145 */
146 bool is_running() const noexcept;
147
148 // =========================================================================
149 // Service Model Registration
150 // =========================================================================
151
152 /**
153 * @brief Register a Service Model
154 *
155 * Service Models must be registered before start() is called.
156 * Each SM handles one or more RAN function IDs.
157 *
158 * @param sm Service Model to register (ownership transferred)
159 * @return ErrorCode::SUCCESS on success
160 * @return ErrorCode::SM_ALREADY_REGISTERED if RAN function already has SM
161 * @return ErrorCode::STATE_ERROR if agent is already running
162 */
163 ErrorCode register_sm(std::unique_ptr<ServiceModel> sm);
164
165 /**
166 * @brief Get available RAN function IDs
167 *
168 * Returns the RAN function IDs from all registered Service Models.
169 */
170 std::vector<uint32_t> get_available_ran_functions() const;
171
172 /**
173 * @brief Set callback for incoming dApp reports (dApp → RAN).
174 * Call before start(). When a dApp sends a DApp report, this callback is invoked.
175 */
177
178 /**
179 * @brief Set callback for dApp status changes.
180 * Called when a dApp connects, disconnects, subscribes, or unsubscribes.
181 * Call before start().
182 */
184
185 // =========================================================================
186 // Manual Operations
187 // =========================================================================
188
189 /**
190 * @brief Send an indication message to a specific dApp
191 *
192 * @param dapp_id Target dApp identifier
193 * @param ran_function_id RAN function identifier
194 * @param data E3SM-encoded indication data
195 * @return ErrorCode::SUCCESS on success
196 */
198 uint32_t dapp_id,
199 uint32_t ran_function_id,
200 const std::vector<uint8_t>& data
201 );
202
203 /**
204 * @brief Send an xApp control action to a specific dApp coming from the E2SM-DAPP.
205 *
206 * @param dapp_id Target dApp identifier
207 * @param ran_function_id RAN function identifier
208 * @param control_data E3SM-encoded control payload
209 * @param sequence_id Correlation id from the E2SM-DAPP control header, so
210 * the dApp can carry it back on the control it re-issues.
211 * @return ErrorCode::SUCCESS on success
212 */
214 uint32_t dapp_id,
215 uint32_t ran_function_id,
216 const std::vector<uint8_t>& control_data,
217 uint32_t sequence_id
218 );
219
220 /**
221 * @brief Send a message acknowledgment (e.g. ack a control/request from dApp).
222 *
223 * @param request_id ID of the request being acknowledged
224 * @param response_code ResponseCode::POSITIVE (0) or NEGATIVE (1)
225 * @return ErrorCode::SUCCESS on success
226 */
227 ErrorCode send_message_ack(uint32_t request_id, ResponseCode response_code);
228
229 // =========================================================================
230 // dApp-role API (used when E3Config.role == E3Role::DAPP)
231 //
232 // Calling these on a RAN-role agent returns STATE_ERROR. Setters can be
233 // called before start(); they're stored and forwarded to the interface
234 // once init() runs.
235 // =========================================================================
236
237 /** Set callback for incoming SetupResponse (RAN → dApp). */
239 /** Set callback for incoming SubscriptionResponse (RAN → dApp). */
241 /** Set callback for incoming IndicationMessage (RAN → dApp). */
243 /** Set callback for incoming XAppControlAction (xApp → dApp via RAN). */
245 /** Set callback for incoming MessageAck (RAN → dApp). */
247
248 /**
249 * @brief dApp identifier assigned by the RAN in SetupResponse.
250 * @return nullopt until setup completes (or on RAN-role agents).
251 */
252 std::optional<uint32_t> dapp_id() const noexcept;
253
254 /** RAN functions this dApp is currently subscribed to. */
255 std::vector<uint32_t> subscribed_ran_functions() const;
256
257 /** Subscription IDs this dApp currently holds. */
258 std::vector<uint32_t> active_subscription_ids() const;
259
260 /**
261 * @brief Block until the dApp setup handshake completes.
262 * @return SUCCESS on positive SetupResponse, CONNECTION_FAILED on negative,
263 * TIMEOUT if the wait elapses, INVALID_PARAM on RAN-role.
264 */
265 ErrorCode wait_for_setup(std::chrono::milliseconds timeout);
266
267 /**
268 * @brief Subscribe to a RAN function. Must be called after a positive setup.
269 *
270 * @param out_request_id when non-null, receives the assigned E3-MessageID on
271 * success, so the caller can correlate the SubscriptionResponse
272 * (which echoes request_id) back to this subscribe call.
273 */
274 ErrorCode subscribe(uint32_t ran_function_id,
275 std::vector<uint32_t> telemetry_ids,
276 std::vector<uint32_t> control_ids,
277 std::optional<uint32_t> sub_time = std::nullopt,
278 std::optional<uint32_t> periodicity = std::nullopt,
279 uint32_t* out_request_id = nullptr);
280
281 /** Send a SubscriptionDelete for a previously subscribed RAN function. */
282 ErrorCode unsubscribe(uint32_t ran_function_id);
283
284 /**
285 * @brief Send a dApp control action to the RAN.
286 *
287 * @param sequence_id correlation id of the xApp procedure this control
288 * re-issues; leave 0 for a control the dApp decided on its own.
289 * @param out_message_id when non-null, receives the assigned E3-MessageID on
290 * success, so the caller can correlate a later ack/response back to
291 * this send.
292 */
293 ErrorCode send_control(uint32_t ran_function_id,
294 uint32_t control_id,
295 std::vector<uint8_t> action_data,
296 uint32_t sequence_id = 0,
297 uint32_t* out_message_id = nullptr);
298
299 /**
300 * @brief Send a dApp report to the RAN.
301 *
302 * @param sequence_id correlation id the dApp assigns to this detection. It
303 * is the head of the loop's chain and is mandatory on the wire.
304 * @param out_message_id when non-null, receives the assigned E3-MessageID on
305 * success, so the caller can correlate a later ack/response back to
306 * this send.
307 */
308 ErrorCode send_report(uint32_t ran_function_id,
309 std::vector<uint8_t> report_data,
310 uint32_t sequence_id,
311 uint32_t* out_message_id = nullptr);
312
313 /** Send a ReleaseMessage. The dApp stays running until stop() is called. */
315
316 /**
317 * @brief Get list of registered dApp IDs
318 */
319 std::vector<uint32_t> get_registered_dapps() const;
320
321 /**
322 * @brief Get subscriptions for a dApp
323 *
324 * @param dapp_id dApp identifier
325 * @return List of RAN function IDs the dApp is subscribed to
326 */
327 std::vector<uint32_t> get_dapp_subscriptions(uint32_t dapp_id) const;
328
329 /**
330 * @brief Get subscribers for a RAN function
331 *
332 * @param ran_function_id RAN function identifier
333 * @return List of dApp IDs subscribed to this RAN function
334 */
335 std::vector<uint32_t> get_ran_function_subscribers(
336 uint32_t ran_function_id
337 ) const;
338
339 /**
340 * @brief Get the RAN functions that currently have at least one subscriber
341 *
342 * RAN role only. Unlike get_available_ran_functions() (which lists every
343 * registered Service Model), this returns only the RAN functions a dApp is
344 * actively subscribed to.
345 *
346 * @return List of RAN function IDs with one or more subscribers
347 */
348 std::vector<uint32_t> get_active_ran_functions() const;
349
350 /**
351 * @brief Get the reporting periodicity a dApp requested for a RAN function
352 *
353 * @return periodicity in microseconds, 0 if not set or subscription not found
354 */
356 uint32_t dapp_id, uint32_t ran_function_id
357 ) const;
358
359 /**
360 * @brief Get the telemetry IDs a dApp requested for a RAN function
361 *
362 * @return vector of telemetry IDs (empty if none requested or subscription not found)
363 */
364 std::vector<uint32_t> get_subscription_telemetry_ids(
365 uint32_t dapp_id, uint32_t ran_function_id
366 ) const;
367
368 /**
369 * @brief Get the control IDs a dApp requested for a RAN function
370 *
371 * @return vector of control IDs (empty if none requested or subscription not found)
372 */
373 std::vector<uint32_t> get_subscription_control_ids(
374 uint32_t dapp_id, uint32_t ran_function_id
375 ) const;
376
377 // =========================================================================
378 // Configuration
379 // =========================================================================
380
381 /**
382 * @brief Get current configuration
383 */
384 const E3Config& config() const noexcept;
385
386 // =========================================================================
387 // Statistics
388 // =========================================================================
389
390 /**
391 * @brief Get number of registered dApps
392 */
393 size_t dapp_count() const;
394
395 /**
396 * @brief Get total number of active subscriptions
397 */
398 size_t subscription_count() const;
399
400private:
401 struct Impl;
402 std::unique_ptr<Impl> impl_;
403};
404
405} // namespace libe3
406
407#endif // LIBE3_E3_AGENT_HPP
std::vector< uint32_t > get_registered_dapps() const
Get list of registered dApp IDs.
Definition e3_agent.cpp:262
E3Agent(E3Agent &&) noexcept
void stop()
Stop the agent.
Definition e3_agent.cpp:127
ErrorCode subscribe(uint32_t ran_function_id, std::vector< uint32_t > telemetry_ids, std::vector< uint32_t > control_ids, std::optional< uint32_t > sub_time=std::nullopt, std::optional< uint32_t > periodicity=std::nullopt, uint32_t *out_request_id=nullptr)
Subscribe to a RAN function. Must be called after a positive setup.
Definition e3_agent.cpp:411
std::vector< uint32_t > get_subscription_telemetry_ids(uint32_t dapp_id, uint32_t ran_function_id) const
Get the telemetry IDs a dApp requested for a RAN function.
Definition e3_agent.cpp:299
void set_xapp_control_handler(XAppControlHandler handler)
Definition e3_agent.cpp:376
void set_setup_response_handler(SetupResponseHandler handler)
Definition e3_agent.cpp:355
ErrorCode wait_for_setup(std::chrono::milliseconds timeout)
Block until the dApp setup handshake completes.
Definition e3_agent.cpp:405
bool is_running() const noexcept
Check if agent is running.
Definition e3_agent.cpp:144
std::vector< uint32_t > subscribed_ran_functions() const
Definition e3_agent.cpp:395
void set_dapp_status_changed_handler(DAppStatusChangedHandler handler)
Set callback for dApp status changes. Called when a dApp connects, disconnects, subscribes,...
Definition e3_agent.cpp:186
std::optional< uint32_t > dapp_id() const noexcept
dApp identifier assigned by the RAN in SetupResponse.
Definition e3_agent.cpp:390
std::vector< uint32_t > get_available_ran_functions() const
Get available RAN function IDs.
Definition e3_agent.cpp:172
std::vector< uint32_t > get_dapp_subscriptions(uint32_t dapp_id) const
Get subscriptions for a dApp.
Definition e3_agent.cpp:269
E3Agent(E3Config config=E3Config{})
Construct an E3Agent with configuration.
Definition e3_agent.cpp:41
ErrorCode release()
Definition e3_agent.cpp:451
std::vector< uint32_t > active_subscription_ids() const
Definition e3_agent.cpp:400
std::vector< uint32_t > get_ran_function_subscribers(uint32_t ran_function_id) const
Get subscribers for a RAN function.
Definition e3_agent.cpp:276
uint32_t get_subscription_periodicity(uint32_t dapp_id, uint32_t ran_function_id) const
Get the reporting periodicity a dApp requested for a RAN function.
Definition e3_agent.cpp:290
ErrorCode register_sm(std::unique_ptr< ServiceModel > sm)
Register a Service Model.
Definition e3_agent.cpp:152
ErrorCode unsubscribe(uint32_t ran_function_id)
Definition e3_agent.cpp:424
size_t dapp_count() const
Get number of registered dApps.
Definition e3_agent.cpp:329
void set_subscription_response_handler(SubscriptionResponseHandler handler)
Definition e3_agent.cpp:362
E3Agent & operator=(const E3Agent &)=delete
~E3Agent()
Destructor - ensures clean shutdown.
Definition e3_agent.cpp:47
const E3Config & config() const noexcept
Get current configuration.
Definition e3_agent.cpp:321
std::vector< uint32_t > get_subscription_control_ids(uint32_t dapp_id, uint32_t ran_function_id) const
Get the control IDs a dApp requested for a RAN function.
Definition e3_agent.cpp:308
ErrorCode send_report(uint32_t ran_function_id, std::vector< uint8_t > report_data, uint32_t sequence_id, uint32_t *out_message_id=nullptr)
Send a dApp report to the RAN.
Definition e3_agent.cpp:441
E3Agent(const E3Agent &)=delete
ErrorCode send_indication(uint32_t dapp_id, uint32_t ran_function_id, const std::vector< uint8_t > &data)
Send an indication message to a specific dApp.
Definition e3_agent.cpp:197
std::vector< uint32_t > get_active_ran_functions() const
Get the RAN functions that currently have at least one subscriber.
Definition e3_agent.cpp:283
ErrorCode send_xapp_control(uint32_t dapp_id, uint32_t ran_function_id, const std::vector< uint8_t > &control_data, uint32_t sequence_id)
Send an xApp control action to a specific dApp coming from the E2SM-DAPP.
Definition e3_agent.cpp:226
ErrorCode send_control(uint32_t ran_function_id, uint32_t control_id, std::vector< uint8_t > action_data, uint32_t sequence_id=0, uint32_t *out_message_id=nullptr)
Send a dApp control action to the RAN.
Definition e3_agent.cpp:430
void set_indication_handler(IndicationHandler handler)
Definition e3_agent.cpp:369
AgentState state() const noexcept
Get current agent state.
Definition e3_agent.cpp:137
void set_dapp_report_handler(DAppReportHandler handler)
Set callback for incoming dApp reports (dApp → RAN). Call before start(). When a dApp sends a DApp re...
Definition e3_agent.cpp:179
ErrorCode init()
Initialize the agent.
Definition e3_agent.cpp:59
void set_message_ack_handler(MessageAckHandler handler)
Definition e3_agent.cpp:383
size_t subscription_count() const
Get total number of active subscriptions.
Definition e3_agent.cpp:341
ErrorCode start()
Start the agent.
Definition e3_agent.cpp:105
ErrorCode send_message_ack(uint32_t request_id, ResponseCode response_code)
Send a message acknowledgment (e.g. ack a control/request from dApp).
Definition e3_agent.cpp:249
E3Interface - Internal protocol coordination.
Abstract Service Model interface.
std::function< void(const SubscriptionResponse &)> SubscriptionResponseHandler
Definition e3_agent.hpp:37
ErrorCode
Error codes returned by libe3 operations Use shared error-code list (see libe3/error_codes....
Definition types.hpp:141
std::function< void(const XAppControlAction &)> XAppControlHandler
Definition e3_agent.hpp:39
AgentState
Agent state machine states.
Definition types.hpp:126
std::function< void()> DAppStatusChangedHandler
Definition e3_agent.hpp:33
ResponseCode
E3AP response codes.
Definition types.hpp:101
std::function< void(const DAppReport &)> DAppReportHandler
Definition e3_agent.hpp:30
std::function< void(const SetupResponse &)> SetupResponseHandler
Definition e3_agent.hpp:36
std::function< void(const MessageAck &)> MessageAckHandler
Definition e3_agent.hpp:40
std::function< void(const IndicationMessage &)> IndicationHandler
Definition e3_agent.hpp:38
Service Model Interface - Extension point for RAN vendors.
E3AP dApp Report structure.
Definition types.hpp:293
E3Agent implementation details.
Definition e3_agent.cpp:24
Configuration for E3Agent.
Definition types.hpp:390
E3AP Indication Message structure.
Definition types.hpp:263
E3AP Message Acknowledgment structure.
Definition types.hpp:285
E3AP Setup Response structure.
Definition types.hpp:221
E3AP Subscription Response structure.
Definition types.hpp:253
E3AP xApp Control Action structure.
Definition types.hpp:306
E3AP Protocol Types - Vendor-neutral type definitions.