PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
ethernetPacketBackend.h
Go to the documentation of this file.
1
3
4#pragma once
5
6#if defined(_WIN32)
7#ifndef WIN32_LEAN_AND_MEAN
8#define WIN32_LEAN_AND_MEAN
9#endif
10#ifndef NOMINMAX
11#define NOMINMAX
12#endif
13#include <winsock2.h>
14#include <windows.h>
15#endif
16
17#include <pcap.h>
18
19#include <asio/error_code.hpp>
20#include <asio/io_context.hpp>
21#include <asio/steady_timer.hpp>
22
23#include <atomic>
24#include <chrono>
25#include <exception>
26#include <future>
27#include <memory>
28#include <mutex>
29#include <string>
30#include <vector>
31
33
34#if defined(_WIN32)
35#include <asio/windows/object_handle.hpp>
36#else
37#include <asio/posix/stream_descriptor.hpp>
38#endif
39
40namespace profinet
41{
56{
57 public:
66 EthernetPacketBackend(asio::io_context& ioContext, const std::string& interface, std::uint16_t ethertype);
67
70
73
76
81 void Send(const std::vector<std::uint8_t>& frame);
82
86 void SetTimeout(std::chrono::milliseconds newTimeout);
87
92 [[nodiscard]] std::vector<std::uint8_t> Recv();
93
94 private:
101 {
102 enum class State : std::uint8_t
103 {
104 Pending,
105 Received,
106 TimedOut,
107 Failed
108 };
109
112 explicit ReceiveOperation(asio::io_context& ioContext)
114 {
115 }
116
118 std::atomic<State> state{State::Pending};
119
121 std::atomic<std::size_t> pendingHandlers{0U};
122
124 std::promise<std::vector<std::uint8_t>> completion;
125
127 std::vector<std::uint8_t> frame;
128
130 std::exception_ptr error;
131
133 std::mutex resultMutex;
134
136 asio::steady_timer timeoutTimer;
137
139 asio::steady_timer pollTimer;
140 };
141
145 void OpenCapture(const std::string& interface);
146
151
155 void AsyncWaitForPacket(const std::shared_ptr<ReceiveOperation>& operation);
156
161 void HandlePacketReady(const std::shared_ptr<ReceiveOperation>& operation, const asio::error_code& error);
162
167 void HandleTimeout(const std::shared_ptr<ReceiveOperation>& operation, const asio::error_code& error);
168
172 void RearmPacketWait(const std::shared_ptr<ReceiveOperation>& operation);
173
178 void FailOperation(const std::shared_ptr<ReceiveOperation>& operation, std::exception_ptr error);
179
184 void CancelPacketWait(const std::shared_ptr<ReceiveOperation>& operation, asio::error_code& error);
185
189 void CompleteHandler(const std::shared_ptr<ReceiveOperation>& operation);
190
195 int CaptureNextFrame(std::vector<std::uint8_t>& frame);
196
202
207 [[nodiscard]] bool MatchesEtherType(const std::vector<std::uint8_t>& frame) const;
208
210 asio::io_context& ioContext;
211
213 pcap_t* capture{nullptr};
214
216 std::uint16_t ethertype{0U};
217
219 std::chrono::milliseconds timeout{std::chrono::milliseconds::zero()};
220
222 std::mutex timeoutMutex;
223
225 std::mutex captureMutex;
226
228 std::mutex receiveMutex;
229
231 bool usePolling{false};
232
233#if defined(_WIN32)
235 asio::windows::object_handle packetWait;
236#else
238 asio::posix::stream_descriptor packetWait;
239#endif
240};
241
242} // namespace profinet
Asio-backed platform-independent raw Ethernet transport.
Private packet-capture backend for complete Ethernet frames.
void HandleTimeout(const std::shared_ptr< ReceiveOperation > &operation, const asio::error_code &error)
Handle application receive timeout.
void SetTimeout(std::chrono::milliseconds newTimeout)
Configure the receive timeout.
EthernetPacketBackend & operator=(EthernetPacketBackend &&)=delete
void RearmPacketWait(const std::shared_ptr< ReceiveOperation > &operation)
Rearm packet readiness for another asynchronous operation.
std::uint16_t ethertype
Configured Ethernet EtherType filter.
std::mutex captureMutex
Serializes libpcap operations.
void CancelPacketWait(const std::shared_ptr< ReceiveOperation > &operation, asio::error_code &error)
Cancel the current packet readiness operation.
void FailOperation(const std::shared_ptr< ReceiveOperation > &operation, std::exception_ptr error)
Mark a receive operation as failed.
std::vector< std::uint8_t > Recv()
Receive a complete Ethernet frame.
bool MatchesEtherType(const std::vector< std::uint8_t > &frame) const
Check whether an Ethernet frame matches the configured EtherType.
void OpenCapture(const std::string &interface)
Initialize the libpcap packet capture handle.
void Send(const std::vector< std::uint8_t > &frame)
Send one complete Ethernet frame.
bool usePolling
True when packet readiness must use timer polling.
int CaptureNextFrame(std::vector< std::uint8_t > &frame)
Read one packet from libpcap without blocking.
std::mutex receiveMutex
Prevents multiple simultaneous Recv() operations.
asio::io_context & ioContext
Asio execution context.
void CompleteHandler(const std::shared_ptr< ReceiveOperation > &operation)
Complete one asynchronous handler.
EthernetPacketBackend & operator=(const EthernetPacketBackend &)=delete
void HandlePacketReady(const std::shared_ptr< ReceiveOperation > &operation, const asio::error_code &error)
Handle packet-source readiness.
EthernetPacketBackend(EthernetPacketBackend &&)=delete
EthernetPacketBackend(const EthernetPacketBackend &)=delete
void InitializePacketWait()
Connect the packet source to the Asio readiness mechanism.
asio::posix::stream_descriptor packetWait
Asio wrapper around the duplicated libpcap selectable descriptor.
std::chrono::milliseconds timeout
Current receive timeout.
std::mutex timeoutMutex
Protects access to the receive timeout.
void AsyncWaitForPacket(const std::shared_ptr< ReceiveOperation > &operation)
Start waiting until a packet source becomes readable.
Shared fixture for EthernetPacketBackend tests.
asio::error_code error
Receive operation state shared by all asynchronous handlers.
asio::steady_timer timeoutTimer
Application-level receive timeout.
ReceiveOperation(asio::io_context &ioContext)
Construct a receive operation with timers on the supplied context.
std::atomic< State > state
Completion state shared between asynchronous handlers.
std::mutex resultMutex
Protects frame and error completion data.
std::exception_ptr error
Exception produced by a failed receive.
std::promise< std::vector< std::uint8_t > > completion
Wait used by the synchronous Recv() API.
asio::steady_timer pollTimer
Polling fallback timer for non-selectable packet sources.
std::atomic< std::size_t > pendingHandlers
Number of outstanding asynchronous handlers.
std::vector< std::uint8_t > frame
Frame received by the packet handler.
Bytes frame