4#include "Stroika/Foundation/StroikaPreComp.h"
8#if qStroika_Foundation_Common_Platform_POSIX
12#include <netinet/in.h>
14#include <sys/socket.h>
16#if qStroika_Foundation_Common_Platform_Linux
17#include <linux/netlink.h>
18#include <linux/rtnetlink.h>
20#elif qStroika_Foundation_Common_Platform_Windows
30#include "Stroika/Foundation/Containers/Collection.h"
31#include "Stroika/Foundation/Execution/Exceptions.h"
33#if qStroika_Foundation_Common_Platform_Windows
34#include "Platform/Windows/WinSock.h"
35#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
39#include "ConnectionlessSocket.h"
48using namespace Stroika::Foundation::Memory;
49using namespace Stroika::Foundation::IO;
55#pragma comment(lib, "Iphlpapi.lib")
63#include <netinet/in.h>
67#include <sys/socket.h>
71static const char* flags (
int sd,
const char* name)
73 static char buf[1024];
75 static struct ifreq ifreq;
76 strcpy (ifreq.ifr_name, name);
78 int r = ioctl (sd, SIOCGIFFLAGS, (
char*)&ifreq);
83 if (ifreq.ifr_flags & b) \
84 l += snprintf (buf + l, sizeof (buf) - l, #b " ")
89 FLAG (IFF_POINTOPOINT);
93 FLAG (IFF_NOTRAILERS);
108 static struct ifreq ifreqs[32] {};
109 struct ifconf ifconf {};
110 ifconf.ifc_req = ifreqs;
111 ifconf.ifc_len =
sizeof(ifreqs);
113 int sd = ::socket (PF_INET, SOCK_STREAM, 0);
116 int r = ioctl (sd, SIOCGIFCONF, (
char*)&ifconf);
119 for (
int i = 0; i < ifconf.ifc_len /
sizeof(
struct ifreq); ++i) {
120 printf (
"%s: %s\n", ifreqs[i].ifr_name, inet_ntoa (((
struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr));
121 printf (
" flags: %s\n", flags (sd, ifreqs[i].ifr_name));
130#if qStroika_Foundation_Common_Platform_Windows
137#if USE_NOISY_TRACE_IN_THIS_MODULE_
141#if qStroika_Foundation_Common_Platform_Windows
142 IO::Network::Platform::Windows::WinSock::AssureStarted ();
144 DWORD TEST = GetComputerNameEx((COMPUTER_NAME_FORMAT)cnf, buffer, &dwSize))
147 if (::gethostname (ac,
sizeof (ac)) == SOCKET_ERROR) {
148 DbgTrace (
"gethostname: err={}"_f, WSAGetLastError ());
153 if (
auto f = allNotLocal.
First ()) {
156 if (
auto f = allAddrs.
First ()) {
160#elif qStroika_Foundation_Common_Platform_POSIX
161 auto getFlags = [] (
int sd,
const char* name) ->
int {
162 struct ::ifreq ifreq{};
163 Characters::CString::Copy (ifreq.ifr_name, NEltsOf (ifreq.ifr_name), name);
164 int r = ::ioctl (sd, SIOCGIFFLAGS, (
char*)&ifreq);
168 DbgTrace (
"ioctl on getFlags returned {}, errno={}"_f, r, errno);
172 return ifreq.ifr_flags;
175 struct ::ifreq ifreqs[32]{};
176 struct ::ifconf ifconf{};
177 ifconf.ifc_req = ifreqs;
178 ifconf.ifc_len =
sizeof (ifreqs);
180 int sd = ::socket (PF_INET, SOCK_STREAM, 0);
183 [[maybe_unused]]
int r = ::ioctl (sd, SIOCGIFCONF, (
char*)&ifconf);
187 for (
int i = 0; i < ifconf.ifc_len /
sizeof (
struct ifreq); ++i) {
188 int flags = getFlags (sd, ifreqs[i].ifr_name);
189 if ((flags & IFF_UP) and (not(flags & IFF_LOOPBACK)) and (flags & IFF_RUNNING)) {
190 result =
InternetAddress{((
struct sockaddr_in*)&ifreqs[i].ifr_addr)->sin_addr};
201String Network::GetPrimaryNetworkDeviceMacAddress ()
203#if USE_NOISY_TRACE_IN_THIS_MODULE_
206 [[maybe_unused]]
auto printMacAddr = [] (
const uint8_t macaddrBytes[6]) ->
String {
208 (void)std::snprintf (buf,
sizeof (buf),
"%02x:%02x:%02x:%02x:%02x:%02x", macaddrBytes[0], macaddrBytes[1], macaddrBytes[2],
209 macaddrBytes[3], macaddrBytes[4], macaddrBytes[5]);
212#if qStroika_Foundation_Common_Platform_Linux
219 ifc.ifc_len =
sizeof (buf);
223 const struct ifreq*
const end = ifc.ifc_req + (ifc.ifc_len /
sizeof (
struct ifreq));
224 for (
const ifreq* it = ifc.ifc_req; it != end; ++it) {
226 Characters::CString::Copy (ifr.ifr_name, NEltsOf (ifr.ifr_name), it->ifr_name);
228 if (!(ifr.ifr_flags & IFF_LOOPBACK)) {
230 return printMacAddr (
reinterpret_cast<const uint8_t*
> (ifr.ifr_hwaddr.sa_data));
236#elif qStroika_Foundation_Common_Platform_Windows
237 IP_ADAPTER_INFO adapterInfo[10];
238 DWORD dwBufLen =
sizeof (adapterInfo);
240 for (PIP_ADAPTER_INFO pi = adapterInfo; pi !=
nullptr; pi = pi->Next) {
243 return printMacAddr (pi->Address);
251struct LinkMonitor::Rep_ {
252 void AddCallback (
const Callback& callback)
254 fCallbacks_.Add (callback);
255 StartMonitorIfNeeded_ ();
257 void RemoveCallback (
const Callback& callback)
259 fCallbacks_.Remove (callback);
263#if qStroika_Foundation_Common_Platform_POSIX
266#if qStroika_Foundation_Common_Platform_Windows
267 HANDLE fMonitorHandler_ = INVALID_HANDLE_VALUE;
270 void SendNotifies (LinkChange lc,
const String& linkName,
const String& ipAddr)
272 for (
const auto& cb : fCallbacks_) {
273 cb (lc, linkName, ipAddr);
277#if qStroika_Foundation_Common_Platform_Windows
279 static void WINAPI CB_ (
void* callerContext, PMIB_UNICASTIPADDRESS_ROW Address, MIB_NOTIFICATION_TYPE NotificationType)
281 Rep_* rep =
reinterpret_cast<Rep_*
> (callerContext);
282 if (Address != NULL) {
283 char ipAddrBuf[1024];
284 (void)snprintf (ipAddrBuf, NEltsOf (ipAddrBuf),
"%d.%d.%d.%d", Address->Address.Ipv4.sin_addr.s_net,
285 Address->Address.Ipv4.sin_addr.s_host, Address->Address.Ipv4.sin_addr.s_lh, Address->Address.Ipv4.sin_addr.s_impno);
286 LinkChange lc = (NotificationType == MibDeleteInstance) ? LinkChange::eRemoved : LinkChange::eAdded;
292 void StartMonitorIfNeeded_ ()
294#if qStroika_Foundation_Common_Platform_Linux
295 if (fMonitorThread_ ==
nullptr) {
305 addr.nl_family = AF_NETLINK;
306 addr.nl_groups = RTMGRP_IPV4_IFADDR;
317 struct nlmsghdr* nlh;
318 nlh = (
struct nlmsghdr*)buffer;
320 while ((NLMSG_OK (nlh, len)) and (nlh->nlmsg_type != NLMSG_DONE)) {
321 if (nlh->nlmsg_type == RTM_NEWADDR) {
322 struct ifaddrmsg* ifa = (
struct ifaddrmsg*)NLMSG_DATA (nlh);
323 struct rtattr* rth = IFA_RTA (ifa);
324 int rtl = IFA_PAYLOAD (nlh);
325 while (rtl and RTA_OK (rth, rtl)) {
326 if (rth->rta_type == IFA_LOCAL) {
327 DISABLE_COMPILER_CLANG_WARNING_START (
"clang diagnostic ignored \"-Wdeprecated\"");
328 uint32_t ipaddr = htonl (*((uint32_t*)RTA_DATA (rth)));
329 DISABLE_COMPILER_CLANG_WARNING_END (
"clang diagnostic ignored \"-Wdeprecated\"");
331 ::if_indextoname (ifa->ifa_index, name);
333 char ipAddrBuf[1024];
334 ::snprintf (ipAddrBuf, NEltsOf (ipAddrBuf),
"%d.%d.%d.%d", (ipaddr >> 24) & 0xff,
335 (ipaddr >> 16) & 0xff, (ipaddr >> 8) & 0xff, ipaddr & 0xff);
339 rth = RTA_NEXT (rth, rtl);
342 nlh = NLMSG_NEXT (nlh, len);
346 fMonitorThread_.
SetThreadName (
"Network LinkMonitor thread"sv);
347 fMonitorThread_.
Start ();
349#elif qStroika_Foundation_Common_Platform_Windows
354 if (fMonitorHandler_ == INVALID_HANDLE_VALUE) {
364#if qStroika_Foundation_Common_Platform_POSIX
366 if (fMonitorThread_ !=
nullptr) {
369#elif qStroika_Foundation_Common_Platform_Windows
370 if (fMonitorHandler_ != INVALID_HANDLE_VALUE) {
374 ::CancelMibChangeNotify2 (fMonitorHandler_);
385LinkMonitor::LinkMonitor ()
386 : fRep_{make_shared<Rep_> ()}
390void LinkMonitor::AddCallback (
const Callback& callback)
392 fRep_->AddCallback (callback);
395void LinkMonitor::RemoveCallback (
const Callback& callback)
397 fRep_->RemoveCallback (callback);
#define AssertNotImplemented()
String is like std::u32string, except it is much easier to use, often much more space efficient,...
static String FromNarrowSDKString(const char *from)
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual optional< value_type > First() const
nonvirtual RESULT_CONTAINER Where(INCLUDE_PREDICATE &&includeIfTrue) const
Thread::Ptr is a (unsynchronized) smart pointer referencing an internally synchronized std::thread ob...
nonvirtual void SetThreadName(const Characters::String &threadName) const
nonvirtual void Start() const
nonvirtual void AbortAndWaitForDone(Time::DurationSeconds timeout=Time::kInfinity) const
Abort () the thread, and then WaitForDone () - but if doesn't finish fast enough, send extra aborts (...
nonvirtual Sequence< InternetAddress > GetHostAddresses(const String &hostNameOrAddress) const
simple wrapper on GetHostEntry - looking up the hostname/ip address and returning the list of associa...
nonvirtual bool IsLinkLocalAddress() const
nonvirtual PlatformNativeHandle GetNativeSocket() const
FamilyType
Socket address family - also sometimes referred to as domain (argument to ::socket calls it domain)
Create a format-string (see std::wformat_string or Stroika FormatString, or python 'f' strings.
Ptr New(const function< void()> &fun2CallOnce, const optional< Characters::String > &name, const optional< Configuration > &configuration)
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)
ConnectionlessSocket::Ptr New(SocketAddress::FamilyType family, Type socketKind, const optional< IPPROTO > &protocol=nullopt)
InternetAddress GetPrimaryInternetAddress()