Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
LocationProvider.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_UPnP_SSDP_Server_LocationProvider_h_
5#define _Stroika_Frameworks_UPnP_SSDP_Server_LocationProvider_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
9#include <functional>
10#include <optional>
11
15#include "Stroika/Foundation/IO/Network/SocketAddress.h"
18
19/*
20 * \file
21 *
22 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
23 */
24
25namespace Stroika::Frameworks::UPnP::SSDP::Server {
26
27 using Foundation::Characters::String;
28 using Foundation::IO::Network::InternetAddress;
29 using Foundation::IO::Network::SocketAddress;
30 using Foundation::IO::Network::URI;
31
32 /**
33 * What SSDP knows when it is about to advertise - for a LocationProvider to choose the LOCATION by.
34 */
36 /**
37 * This machine's address on the network the advertisement goes to: for a NOTIFY, an address of the interface it goes
38 * out of; for a search response, the address the asker reaches this machine at - this machine's address on the asker's
39 * own network, found by the asker's subnet, or (the asker further off) the one the routing table picks to reach it
40 * (@see IO::Network::GetLocalAddressToReach).
41 * Of the family (IPv4 or IPv6) of the SSDP channel the advertisement is on - and a link-local IPv6 address only if the
42 * interface has no other.
43 */
45
46 /**
47 * For a search response, who asked; for a NOTIFY, nullopt.
48 */
49 optional<SocketAddress> fAsker;
50
51 /**
52 * @see Characters::ToString ();
53 */
54 nonvirtual String ToString () const;
55 };
56
57 /**
58 * \brief The URL of the device description to advertise in the given context - or nullopt: do not advertise there.
59 *
60 * SSDP advertises a device on every network interface, and answers every asker, and the right LOCATION can differ for
61 * each - and only the application knows where its web server listens, or how it is reached (a port mapping, a reverse
62 * proxy, a host name). So the application supplies it - usually as one of LocationFromBindings, FixedLocation or
63 * LocationFillingInHost.
64 *
65 * Called from SSDP's own threads, so must be safe to call from any thread (the ready-made ones are).
66 */
67 using LocationProvider = function<optional<URI> (const LocationContext& context)>;
68
69 /**
70 * \brief For a web server listening on webServerBindings (e.g. WebServer::ConnectionManager::bindings ()): where it can be
71 * reached at context.fLocalAddress.
72 *
73 * The port is that of the binding on context.fLocalAddress itself, or else of a wildcard binding (V4::kAddrAny or
74 * V6::kAddrAny) of its family; nullopt if there is neither - so a web server listening only on IPv6 is never advertised
75 * over IPv4, and one listening on one address only on that address's network.
76 *
77 * Never for a link-local IPv6 address: its URL would need a zone (http://[fe80::1%25en0]/) naming an interface of THIS
78 * machine, meaningless to the receiver.
79 *
80 * \par Example Usage
81 * \code
82 * WebServer::ConnectionManager deviceWS{SocketAddresses (InternetAddresses_Any (), 8080), routes};
83 * BasicServer ssdpServer{device, deviceDescription, LocationFromBindings (deviceWS.bindings (), "/device.xml"sv)};
84 * // deviceWS listens on every IPv4 and IPv6 address, port 8080 - so on each network this advertises this machine's
85 * // address there:
86 * // on the IPv4 network 192.168.1.x http://192.168.1.5:8080/device.xml
87 * // on an IPv6 network where this machine is 2001:db8::5 http://[2001:db8::5]:8080/device.xml
88 * // on an IPv6 network where it has only a link-local address (fe80::...): nothing
89 * \endcode
90 */
91 LocationProvider LocationFromBindings (const Foundation::Traversal::Iterable<SocketAddress>& webServerBindings,
92 const String& path = "/"sv, const URI::SchemeType& scheme = URI::SchemeType{"http"sv});
93
94 /**
95 * \brief Always url - for when the device is reached at an address that is not this machine's (a port mapping, NAT, a
96 * reverse proxy), or by name.
97 *
98 * \note The same url goes to every network the device is advertised on, and nothing here can check that each of them
99 * can reach it: that depends on the receiver's network (its routes, NAT, its DNS), which this machine cannot see.
100 * So use it only for a URL all of those networks can reach - a name they all resolve, an address routed to from all
101 * of them. To advertise on some networks only, write the LocationProvider: it is told this machine's address on
102 * each candidate network (LocationContext::fLocalAddress), and returns nullopt to skip one.
103 *
104 * \par Example Usage
105 * \code
106 * // the device description is served by a reverse proxy, under a name
107 * BasicServer ssdpServer{device, deviceDescription, FixedLocation (URI{"http://media-server.example:8200/device.xml"sv})};
108 * \endcode
109 *
110 * \par Example Usage
111 * \code
112 * // ... but advertised on the 192.168.1.x network only
113 * static const CIDR kHomeNetwork_{"192.168.1.0/24"sv};
114 * BasicServer ssdpServer{device, deviceDescription, [] (const LocationContext& c) -> optional<URI> {
115 * if (kHomeNetwork_.GetRange ().Contains (c.fLocalAddress)) {
116 * return URI{"http://media-server.example:8200/device.xml"sv};
117 * }
118 * return nullopt; // not this network
119 * }};
120 * \endcode
121 */
122 LocationProvider FixedLocation (const URI& url);
123
124 /**
125 * \brief location itself, if it names a host; else location with its host set to context.fLocalAddress - and then
126 * nullopt for a link-local IPv6 address (@see LocationFromBindings).
127 *
128 * \note Before Stroika v3.0d25 this was BasicServer's only behavior (from Device::fLocation) - except that it filled in
129 * one address for every network, IO::Network::GetPrimaryInternetAddress (), and an IPv4 one even on the IPv6 channel.
130 *
131 * \par Example Usage
132 * \code
133 * // some other web server, on port 8080 of every address this machine has
134 * URI location{URI::SchemeType{"http"sv}, URI::Authority{nullopt, PortType{8080}}, "/device.xml"sv}; // no host
135 * BasicServer ssdpServer{device, deviceDescription, LocationFillingInHost (location)};
136 * // advertises http://192.168.1.5:8080/device.xml on the 192.168.1.x network, http://10.0.0.7:8080/device.xml on 10.0.0.x
137 * \endcode
138 */
139 LocationProvider LocationFillingInHost (const URI& location);
140
141}
142
143/*
144 ********************************************************************************
145 ***************************** Implementation Details ***************************
146 ********************************************************************************
147 */
148#include "LocationProvider.inl"
149
150#endif /*_Stroika_Frameworks_UPnP_SSDP_Server_LocationProvider_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:234