Vanetza
 
Loading...
Searching...
No Matches
pending_packet.hpp
1#ifndef PENDING_PACKET_HPP_ZHSCP1UI
2#define PENDING_PACKET_HPP_ZHSCP1UI
3
4#include <vanetza/common/clock.hpp>
5#include <vanetza/geonet/lifetime.hpp>
6#include <vanetza/geonet/packet.hpp>
7#include <vanetza/units/time.hpp>
8#include <functional>
9#include <memory>
10#include <tuple>
11
12namespace vanetza
13{
14namespace geonet
15{
16
17/**
18 * PendingPacket combines PDU, payload and custom action code for pending processing steps.
19 * This makes it easy to resume packet forwarding steps after buffering, for example.
20 */
21template<typename PDU, typename... Args>
23{
24public:
25 using Packet = std::tuple<std::unique_ptr<PDU>, std::unique_ptr<DownPacket>>;
26 using Function = std::function<void(Packet&&, Args&&...)>;
27
28 PendingPacket() = default;
29
30 PendingPacket(Packet&& packet, const Function& fn) :
31 m_packet(std::move(packet)), m_function(fn) {}
32
33 template<typename... OtherArgs>
34 PendingPacket(PendingPacket<PDU, OtherArgs...>&& other, std::function<void(PendingPacket<PDU, OtherArgs...>&&, Args&&...)> fn) :
35 m_packet(std::move(other).packet())
36 {
37 auto other_fn = other.action();
38 m_function = [fn, other_fn](Packet&& packet, Args&&... args) {
39 fn(PendingPacket<PDU, OtherArgs...> { std::move(packet), other_fn }, std::forward<Args>(args)...);
40 };
41 }
42
43 template<typename... OtherArgs, typename... T>
45 m_packet(std::move(other).packet())
46 {
47 typename PendingPacket<PDU, OtherArgs...>::Function other_action = other.action();
48 std::function<void(Packet&&)> bound = std::bind(other_action, std::placeholders::_1, std::forward<T>(ts)...);
49 m_function = [bound](Packet&& packet, Args&&... args) {
50 bound(std::move(packet), std::forward<Args>(args)...);
51 };
52 }
53
54 void process(Args&&... args)
55 {
56 if (std::get<0>(m_packet) && std::get<1>(m_packet)) {
57 m_function(std::move(m_packet), std::forward<Args>(args)...);
58 }
59 }
60
61 std::size_t length() const
62 {
63 const PDU* pdu = std::get<0>(m_packet).get();
64 const DownPacket* payload = std::get<1>(m_packet).get();
65 return (pdu ? get_length(*pdu) : 0) + (payload ? payload->size(OsiLayer::Transport, max_osi_layer()) : 0);
66 }
67
68 Clock::duration reduce_lifetime(Clock::duration queuing_time)
69 {
70 Clock::duration remaining = Clock::duration::zero();
71 PDU* pdu_ptr = std::get<0>(m_packet).get();
72 if (pdu_ptr) {
73 using vanetza::units::clock_cast;
74 Clock::duration packet_lifetime = clock_cast(pdu_ptr->basic().lifetime.decode());
75 if (queuing_time <= Clock::duration::zero()) {
76 remaining = packet_lifetime;
77 } else if (queuing_time < packet_lifetime) {
78 remaining = packet_lifetime - queuing_time;
79 pdu_ptr->basic().lifetime.encode(clock_cast(remaining));
80 } else {
81 pdu_ptr->basic().lifetime = Lifetime::zero();
82 }
83 }
84 return remaining;
85 }
86
87 const PDU& pdu() const
88 {
89 const PDU* ptr = std::get<0>(m_packet).get();
90 assert(ptr);
91 return *ptr;
92 }
93
94 const DownPacket& payload() const
95 {
96 const DownPacket* ptr = std::get<1>(m_packet).get();
97 assert(ptr);
98 return *ptr;
99 }
100
101 Function action() const { return m_function; }
102
103 Packet packet() && { return std::move(m_packet); }
104
105 PendingPacket duplicate()
106 {
107 const PDU* pdu_ptr = std::get<0>(m_packet).get();
108 std::unique_ptr<PDU> pdu_dup { pdu_ptr ? new PDU(*pdu_ptr) : nullptr };
109 std::unique_ptr<DownPacket> payload_dup;
110 if (!pdu_ptr || pdu_ptr->secured()) {
111 payload_dup.reset(new DownPacket());
112 } else if (const DownPacket* payload_ptr = std::get<1>(m_packet).get()) {
113 payload_dup = vanetza::duplicate(*payload_ptr);
114 }
115 return PendingPacket(std::make_tuple(std::move(pdu_dup), std::move(payload_dup)), m_function);
116 }
117
118private:
119 Packet m_packet;
120 Function m_function;
121};
122
123} // namespace geonet
124} // namespace vanetza
125
126#endif /* PENDING_PACKET_HPP_ZHSCP1UI */
127
ChunckPacket is a packet consisting of several memory chunks.
std::size_t size() const