Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
PeriodicNotifier.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Stroika/Frameworks/StroikaPreComp.h"
5
10#include "Stroika/Foundation/IO/Network/ConnectionlessSocket.h"
11
14
15#include "PeriodicNotifier.h"
16
17using namespace Stroika::Foundation;
20using namespace Stroika::Foundation::IO;
22
23using namespace Stroika::Frameworks;
24using namespace Stroika::Frameworks::UPnP;
25using namespace Stroika::Frameworks::UPnP::SSDP;
26using namespace Stroika::Frameworks::UPnP::SSDP::Server;
27
28// Comment this in to turn on tracing in this module
29//#define USE_NOISY_TRACE_IN_THIS_MODULE_ 1
30
31/*
32 ********************************************************************************
33 ******************************** PeriodicNotifier ******************************
34 ********************************************************************************
35 */
36PeriodicNotifier::PeriodicNotifier (const Iterable<Advertisement>& advertisements, const FrequencyInfo& fi,
38{
40 advertisements.Apply ([] ([[maybe_unused]] const auto& a) { Require (not a.fTarget.empty ()); });
41 }
42
43 // Construction of notifier will fail if we cannot bind - instead of failing quietly inside the loop
45 {
46 static constexpr Execution::Activity kActivity_{"SSDP Binding in PeriodNotifier"sv};
47 Execution::DeclareActivity da{&kActivity_};
48 if (InternetProtocol::IP::SupportIPV4 (ipVersion)) {
49 ConnectionlessSocket::Ptr s = ConnectionlessSocket::New (SocketAddress::INET, Socket::DGRAM);
50 s.Bind (SocketAddress{Network::V4::kAddrAny, UPnP::SSDP::V4::kSocketAddress.GetPort ()}, Socket::BindFlags{.fSO_REUSEADDR = true});
51 sockets += make_pair (s, UPnP::SSDP::V4::kSocketAddress);
52 }
53 if (InternetProtocol::IP::SupportIPV6 (ipVersion)) {
54 ConnectionlessSocket::Ptr s = ConnectionlessSocket::New (SocketAddress::INET6, Socket::DGRAM);
55 s.Bind (SocketAddress{Network::V6::kAddrAny, UPnP::SSDP::V6::kSocketAddress.GetPort ()}, Socket::BindFlags{.fSO_REUSEADDR = true});
56 sockets += make_pair (s, UPnP::SSDP::V6::kSocketAddress);
57 }
58 }
59
60 if constexpr (qStroika_Foundation_Debug_DefaultTracingOn) {
61 Debug::TraceContextBumper ctx{"SSDP PeriodicNotifier - first time notifications"};
62 for ([[maybe_unused]] const auto& a : advertisements) {
63 DbgTrace ("(alive,loc={},usn={},...)"_f, a.fLocation, a.fUSN);
64 }
65 }
66
67 Execution::IntervalTimer::TimerCallback callback = [=] () mutable {
68#if USE_NOISY_TRACE_IN_THIS_MODULE_
69 Debug::TraceContextBumper ctx{"SSDP PeriodicNotifier - notifications"};
70 for ([[maybe_unused]] const auto& a : advertisements) {
71#if USE_NOISY_TRACE_IN_THIS_MODULE_
72 String msg;
73 msg += "alive," sz;
74 msg += "location=" sz + a.fLocation + ", " sz;
75 msg += "ST=" sz + a.fST + ", " sz;
76 msg += "USN=" sz + a.fUSN;
77 DbgTrace (L"(%s)", msg.c_str ());
78#endif
79 }
80#endif
81 try {
82 for (auto a : advertisements) {
83 a.fAlive = true; // periodic notifier must announce alive (we don't support 'going down' yet)
84 Memory::BLOB data = SSDP::Serialize ("NOTIFY * HTTP/1.1"sv, SearchOrNotify::Notify, a);
85 for (pair<ConnectionlessSocket::Ptr, SocketAddress> s : sockets) {
86 s.first.SendTo (data, s.second);
87 }
88 }
89 }
90 catch (const Execution::Thread::AbortException&) {
92 }
93 catch (...) {
94 DbgTrace ("Ignoring inability to send SSDP notify packets: {} (try again later)"_f, current_exception ());
95 }
96 };
97 fIntervalTimerAdder_ = make_unique<Execution::IntervalTimer::Adder> (callback, Time::Duration{fi.fRepeatInterval},
99}
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
Definition Assertions.h:48
#define DbgTrace
Definition Trace.h:309
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual tuple< const wchar_t *, wstring_view > c_str(Memory::StackBuffer< wchar_t > *possibleBackingStore) const
Definition String.inl:1049
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
Definition Collection.h:102
nonvirtual void Bind(const SocketAddress &sockAddr, BindFlags bindFlags=BindFlags{})
Definition Socket.cpp:212
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
nonvirtual void Apply(const function< void(ArgByValueType< T > item)> &doToElement, Execution::SequencePolicy seq=Execution::SequencePolicy::eDEFAULT) const
Run the argument function (or lambda) on each element of the container.
PeriodicNotifier(const Iterable< Advertisement > &advertisements, const FrequencyInfo &fi, IO::Network::InternetProtocol::IP::IPVersionSupport ipVersion=IO::Network::InternetProtocol::IP::IPVersionSupport::eDEFAULT)
ConnectionlessSocket::Ptr New(SocketAddress::FamilyType family, Type socketKind, const optional< IPPROTO > &protocol=nullopt)
bool SupportIPV4(IPVersionSupport flag)
Definition IP.inl:8