55 const u_int16_t dataId;
59 const u_int32_t eventSrcId;
62 const size_t numSendSockets;
65 const int sndSocketBufSize;
76 const u_int8_t lbHdrVersion;
81 static constexpr unsigned cqeBatchSize{100};
84 static constexpr boost::chrono::milliseconds sleepTime{1};
87 struct EventQueueItem {
93 void (*callback)(boost::any);
98 boost::lockfree::queue<EventQueueItem*, boost::lockfree::fixed_sized<true>> eventQueue;
100#ifdef LIBURING_AVAILABLE
101 std::vector<struct io_uring> rings;
102 std::vector<boost::mutex> ringMtxs;
106 const size_t uringSize = 1000;
112 struct msghdr* msghdr;
113 void (*callback)(boost::any);
121 UnixTimeNano_t lastSyncTimeNanos;
123 EventNum_t eventsSinceLastSync;
126 boost::circular_buffer<SendStats> eventStatsBuffer;
128 boost::atomic<UnixTimeNano_t> currentSyncStartNano{0};
129 boost::atomic<EventNum_t> eventsInCurrentSync{0};
132 boost::atomic<EventNum_t> userEventNum{0};
135 boost::random::ranlux24_base ranlux;
137 boost::random::uniform_int_distribution<> lsbDist{0, 255};
140 size_t roundRobinIndex{0};
148 std::atomic<u_int64_t> msgCnt{0};
150 std::atomic<u_int64_t> errCnt{0};
152 std::atomic<int> lastErrno{0};
154 std::atomic<E2SARErrorc> lastE2SARError{E2SARErrorc::NoError};
157 AtomicStats syncStats;
158 AtomicStats sendStats;
163 struct SyncThreadState {
166 boost::thread threadObj;
168 const u_int16_t period_ms{100};
170 const bool connectSocket{
true};
173#define GET_V4_SYNC_STRUCT(sas) boost::get<sockaddr_in>(sas)
174#define GET_V6_SYNC_STRUCT(sas) boost::get<sockaddr_in6>(sas)
175 boost::variant<sockaddr_in, sockaddr_in6> syncAddrStruct;
181 inline SyncThreadState(
Segmenter &s, u_int16_t time_period_ms,
bool cnct=
true):
183 period_ms{time_period_ms},
188 result<int> _close();
189 result<int> _send(
SyncHdr *hdr);
194 friend struct SyncThreadState;
196 SyncThreadState syncThreadState;
202 struct SendThreadState {
205 boost::thread threadObj;
209 const bool connectSocket{
true};
213 const bool ticksAsREEventNum;
217 std::string iface{
""};
222#define GET_FD(sas, i) boost::get<0>(sas[i])
223#define GET_LOCAL_SEND_STRUCT(sas,i) boost::get<1>(sas[i])
224#define GET_REMOTE_SEND_STRUCT(sas, i) boost::get<2>(sas[i])
225 std::vector<boost::tuple<int, sockaddr_in, sockaddr_in>> socketFd4;
226 std::vector<boost::tuple<int, sockaddr_in6, sockaddr_in6>> socketFd6;
231 boost::random::ranlux24_base ranlux;
232 boost::random::uniform_int_distribution<> randDist{0, std::numeric_limits<u_int16_t>::max()};
234 boost::random::uniform_int_distribution<> portDist{10000, std::numeric_limits<u_int16_t>::max()};
236 inline SendThreadState(
Segmenter &s,
int idx,
bool v6, u_int16_t mtu,
bool tasreenum,
bool cnct=
true):
237 seg{s}, threadIndex{idx}, connectSocket{cnct}, useV6{v6}, ticksAsREEventNum{tasreenum}, mtu{mtu},
238 maxPldLen{mtu - getTotalHeaderLength(v6)}, socketFd4(s.numSendSockets),
239 socketFd6(s.numSendSockets),
240 ranlux{
static_cast<u_int32_t
>(std::time(0))}
243 auto nowT = boost::chrono::system_clock::now();
244 ranlux.seed(boost::chrono::duration_cast<boost::chrono::nanoseconds>(nowT.time_since_epoch()).count());
250 result<int> _close();
252 result<int> _waitAndCloseFd(
int fd);
254 result<int> _send(u_int8_t *event,
size_t bytes, EventNum_t altEventNum, u_int16_t dataId,
255 u_int16_t entropy,
size_t roundRobinIndex, int64_t interFrameSleepUsec = 0,
256 void (*callback)(boost::any) =
nullptr, boost::any cbArg =
nullptr);
259#ifdef LIBURING_AVAILABLE
261 void _reap(
size_t roundRobinIndex);
264 friend struct SendThreadState;
266 SendThreadState sendThreadState;
267 const size_t numSendThreads{1};
272 const std::vector<int> cpuCoreList;
274#ifdef LIBURING_AVAILABLE
277 static constexpr unsigned pollWaitTime{2000};
279 boost::atomic<u_int32_t> outstandingSends{0};
283 boost::mutex sendThreadMtx;
290#define MIN_CLOCK_ENTROPY 6
296 inline void sanityChecks()
298 if (numSendSockets > 128)
299 throw E2SARException(
"Too many sending sockets threads requested, limit 128");
301 if (syncThreadState.period_ms > 10000)
304 if (sendThreadState.mtu > 9000)
313 if (sendThreadState.mtu <= getTotalHeaderLength(sendThreadState.useV6))
314 throw E2SARErrorInfo{E2SARErrorc::SocketError,
"Insufficient MTU length to accommodate headers"};
318 bool threadsStop{
false};
320 bool syncThreadStop{
false};
337 ReportedStats(
const AtomicStats &as): msgCnt{as.msgCnt}, errCnt{as.errCnt},
338 lastErrno{as.lastErrno}, lastE2SARError{as.lastE2SARError}
371 bool connectedSocket;
374 u_int16_t syncPeriodMs;
375 u_int16_t syncPeriods;
377 size_t eventQueueSize;
378 size_t numSendSockets;
379 int sndSocketBufSize;
382 bool ticksAsREEventNum;
383 u_int8_t lbHdrVersion;
387 useCP{
true}, warmUpMs{1000}, syncPeriodMs{1000}, syncPeriods{2}, mtu{1500},
388 eventQueueSize{2047}, numSendSockets{4},sndSocketBufSize{1024*1024*3}, rateGbps{-1.0}, smooth{
false},
389 ticksAsREEventNum{
false}, lbHdrVersion{lbhdrVersion2}, syncV6{
false} {}
394 static result<SegmenterFlags>
getFromINI(
const std::string &iniFile)
noexcept;
407 std::vector<int> cpuCoreList,
438#ifdef LIBURING_AVAILABLE
441 for (
size_t i = 0; i < rings.size(); ++i)
443 io_uring_unregister_files(&rings[i]);
445 io_uring_queue_exit(&rings[i]);
468 result<
int>
sendEvent(u_int8_t *event,
size_t bytes, EventNum_t _eventNumber=0LL,
469 u_int16_t _dataId=0, u_int16_t _entropy=0) noexcept;
483 EventNum_t _eventNum=0LL, u_int16_t _dataId = 0, u_int16_t entropy=0,
484 void (*callback)(boost::any) =
nullptr,
485 boost::any cbArg =
nullptr) noexcept;
506 inline const std::string
getIntf() const noexcept
508 return sendThreadState.iface;
516 return sendThreadState.mtu;
524 return sendThreadState.maxPldLen;
532 return sendThreadState.useV6;
537 inline void stopThreads()
542 while (not eventQueue.empty()) {}
547 sendThreadState.threadObj.join();
549 syncThreadStop =
true;
550 syncThreadState.threadObj.join();
559 inline EventRate_t eventRate(UnixTimeNano_t currentTimeNanos)
562 if (eventStatsBuffer.size() == 0)
564 EventNum_t eventTotal{0LL};
566 for(
auto el: eventStatsBuffer)
569 eventTotal += el.eventsSinceLastSync;
571 auto timeDiff = currentTimeNanos -
572 eventStatsBuffer.begin()->lastSyncTimeNanos;
577 return std::round(
static_cast<float>(eventTotal*1000000000UL)/timeDiff);
582 inline void fillSyncHdr(SyncHdr *hdr, UnixTimeNano_t tnano)
584 EventRate_t reportedRate{1000000};
586 auto nowT = boost::chrono::system_clock::now();
588 EventNum_t reportedEventNum = boost::chrono::duration_cast<boost::chrono::microseconds>(nowT.time_since_epoch()).count();
589 hdr->set(eventSrcId, reportedEventNum, reportedRate, tnano);
599 inline int_least64_t addClockEntropy(int_least64_t clockSample)
601 return (clockSample & ~0xFF) | lsbDist(ranlux);