[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / network / Network.cpp
blob69a15136276d86da3cb03b7a8d149ee991e93ea4
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include <netdb.h>
10 #include <netinet/in.h>
11 #include <sys/socket.h>
12 #include <arpa/inet.h>
14 #include "Network.h"
15 #include "ServiceBroker.h"
16 #include "messaging/ApplicationMessenger.h"
17 #include "network/NetworkServices.h"
18 #include "settings/Settings.h"
19 #include "settings/SettingsComponent.h"
20 #include "utils/log.h"
21 #ifdef TARGET_WINDOWS
22 #include "platform/win32/WIN32Util.h"
23 #include "utils/CharsetConverter.h"
24 #endif
25 #include "utils/StringUtils.h"
26 #include "utils/XTimeUtils.h"
28 /* slightly modified in_ether taken from the etherboot project (http://sourceforge.net/projects/etherboot) */
29 bool in_ether (const char *bufp, unsigned char *addr)
31 if (strlen(bufp) != 17)
32 return false;
34 char c;
35 const char *orig;
36 unsigned char *ptr = addr;
37 unsigned val;
39 int i = 0;
40 orig = bufp;
42 while ((*bufp != '\0') && (i < 6))
44 val = 0;
45 c = *bufp++;
47 if (isdigit(c))
48 val = c - '0';
49 else if (c >= 'a' && c <= 'f')
50 val = c - 'a' + 10;
51 else if (c >= 'A' && c <= 'F')
52 val = c - 'A' + 10;
53 else
54 return false;
56 val <<= 4;
57 c = *bufp;
58 if (isdigit(c))
59 val |= c - '0';
60 else if (c >= 'a' && c <= 'f')
61 val |= c - 'a' + 10;
62 else if (c >= 'A' && c <= 'F')
63 val |= c - 'A' + 10;
64 else if (c == ':' || c == '-' || c == 0)
65 val >>= 4;
66 else
67 return false;
69 if (c != 0)
70 bufp++;
72 *ptr++ = (unsigned char) (val & 0377);
73 i++;
75 if (*bufp == ':' || *bufp == '-')
76 bufp++;
79 if (bufp - orig != 17)
80 return false;
82 return true;
85 CNetworkBase::CNetworkBase() :
86 m_services(new CNetworkServices())
88 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_NETWORKMESSAGE, SERVICES_UP, 0);
91 CNetworkBase::~CNetworkBase()
93 CServiceBroker::GetAppMessenger()->PostMsg(TMSG_NETWORKMESSAGE, SERVICES_DOWN, 0);
96 int CNetworkBase::ParseHex(char *str, unsigned char *addr)
98 int len = 0;
100 while (*str)
102 int tmp;
103 if (str[1] == 0)
104 return -1;
105 if (sscanf(str, "%02x", (unsigned int *)&tmp) != 1)
106 return -1;
107 addr[len] = tmp;
108 len++;
109 str += 2;
112 return len;
115 bool CNetworkBase::GetHostName(std::string& hostname)
117 char hostName[128];
118 if (gethostname(hostName, sizeof(hostName)))
119 return false;
121 #ifdef TARGET_WINDOWS
122 std::string hostStr;
123 g_charsetConverter.systemToUtf8(hostName, hostStr);
124 hostname = hostStr;
125 #else
126 hostname = hostName;
127 #endif
128 return true;
131 bool CNetworkBase::IsLocalHost(const std::string& hostname)
133 if (hostname.empty())
134 return false;
136 if (StringUtils::StartsWith(hostname, "127.")
137 || (hostname == "::1")
138 || StringUtils::EqualsNoCase(hostname, "localhost"))
139 return true;
141 std::string myhostname;
142 if (GetHostName(myhostname)
143 && StringUtils::EqualsNoCase(hostname, myhostname))
144 return true;
146 std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
147 std::vector<CNetworkInterface*>::const_iterator iter = ifaces.begin();
148 while (iter != ifaces.end())
150 CNetworkInterface* iface = *iter;
151 if (iface && iface->GetCurrentIPAddress() == hostname)
152 return true;
154 ++iter;
157 return false;
160 CNetworkInterface* CNetworkBase::GetFirstConnectedInterface()
162 CNetworkInterface* fallbackInterface = nullptr;
163 for (CNetworkInterface* iface : GetInterfaceList())
165 if (iface && iface->IsConnected())
167 if (!iface->GetCurrentDefaultGateway().empty())
168 return iface;
169 else if (fallbackInterface == nullptr)
170 fallbackInterface = iface;
174 return fallbackInterface;
177 bool CNetworkBase::HasInterfaceForIP(unsigned long address)
179 unsigned long subnet;
180 unsigned long local;
181 std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
182 std::vector<CNetworkInterface*>::const_iterator iter = ifaces.begin();
183 while (iter != ifaces.end())
185 CNetworkInterface* iface = *iter;
186 if (iface && iface->IsConnected())
188 subnet = ntohl(inet_addr(iface->GetCurrentNetmask().c_str()));
189 local = ntohl(inet_addr(iface->GetCurrentIPAddress().c_str()));
190 if( (address & subnet) == (local & subnet) )
191 return true;
193 ++iter;
196 return false;
199 bool CNetworkBase::IsAvailable(void)
201 const std::vector<CNetworkInterface*>& ifaces = GetInterfaceList();
202 return (ifaces.size() != 0);
205 bool CNetworkBase::IsConnected()
207 return GetFirstConnectedInterface() != NULL;
210 void CNetworkBase::NetworkMessage(EMESSAGE message, int param)
212 switch( message )
214 case SERVICES_UP:
215 CLog::Log(LOGDEBUG, "{} - Starting network services", __FUNCTION__);
216 m_services->Start();
217 break;
219 case SERVICES_DOWN:
220 CLog::Log(LOGDEBUG, "{} - Signaling network services to stop", __FUNCTION__);
221 m_services->Stop(false); // tell network services to stop, but don't wait for them yet
222 CLog::Log(LOGDEBUG, "{} - Waiting for network services to stop", __FUNCTION__);
223 m_services->Stop(true); // wait for network services to stop
224 break;
228 bool CNetworkBase::WakeOnLan(const char* mac)
230 int i, j, packet;
231 unsigned char ethaddr[8];
232 unsigned char buf [128];
233 unsigned char *ptr;
235 // Fetch the hardware address
236 if (!in_ether(mac, ethaddr))
238 CLog::Log(LOGERROR, "{} - Invalid hardware address specified ({})", __FUNCTION__, mac);
239 return false;
242 // Setup the socket
243 if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
245 CLog::Log(LOGERROR, "{} - Unable to create socket ({})", __FUNCTION__, strerror(errno));
246 return false;
249 // Set socket options
250 struct sockaddr_in saddr;
251 saddr.sin_family = AF_INET;
252 saddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
253 saddr.sin_port = htons(9);
255 unsigned int value = 1;
256 if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char*) &value, sizeof( unsigned int ) ) == SOCKET_ERROR)
258 CLog::Log(LOGERROR, "{} - Unable to set socket options ({})", __FUNCTION__, strerror(errno));
259 closesocket(packet);
260 return false;
263 // Build the magic packet (6 x 0xff + 16 x MAC address)
264 ptr = buf;
265 for (i = 0; i < 6; i++)
266 *ptr++ = 0xff;
268 for (j = 0; j < 16; j++)
269 for (i = 0; i < 6; i++)
270 *ptr++ = ethaddr[i];
272 // Send the magic packet
273 if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&saddr, sizeof (saddr)) < 0)
275 CLog::Log(LOGERROR, "{} - Unable to send magic packet ({})", __FUNCTION__, strerror(errno));
276 closesocket(packet);
277 return false;
280 closesocket(packet);
281 CLog::Log(LOGINFO, "{} - Magic packet send to '{}'", __FUNCTION__, mac);
282 return true;
285 // ping helper
286 static const char* ConnectHostPort(SOCKET soc, const struct sockaddr_in& addr, struct timeval& timeOut, bool tryRead)
288 // set non-blocking
289 #ifdef TARGET_WINDOWS
290 u_long nonblocking = 1;
291 int result = ioctlsocket(soc, FIONBIO, &nonblocking);
292 #else
293 int result = fcntl(soc, F_SETFL, fcntl(soc, F_GETFL) | O_NONBLOCK);
294 #endif
296 if (result != 0)
297 return "set non-blocking option failed";
299 result = connect(soc, (const struct sockaddr *)&addr, sizeof(addr)); // non-blocking connect, will fail ..
301 if (result < 0)
303 #ifdef TARGET_WINDOWS
304 if (WSAGetLastError() != WSAEWOULDBLOCK)
305 #else
306 if (errno != EINPROGRESS)
307 #endif
308 return "unexpected connect fail";
310 { // wait for connect to complete
311 fd_set wset;
312 FD_ZERO(&wset);
313 FD_SET(soc, &wset);
315 result = select(FD_SETSIZE, 0, &wset, 0, &timeOut);
318 if (result < 0)
319 return "select fail";
321 if (result == 0) // timeout
322 return ""; // no error
324 { // verify socket connection state
325 int err_code = -1;
326 socklen_t code_len = sizeof (err_code);
328 result = getsockopt(soc, SOL_SOCKET, SO_ERROR, (char*) &err_code, &code_len);
330 if (result != 0)
331 return "getsockopt fail";
333 if (err_code != 0)
334 return ""; // no error, just not connected
338 if (tryRead)
340 fd_set rset;
341 FD_ZERO(&rset);
342 FD_SET(soc, &rset);
344 result = select(FD_SETSIZE, &rset, 0, 0, &timeOut);
346 if (result > 0)
348 char message [32];
350 result = recv(soc, message, sizeof(message), 0);
353 if (result == 0)
354 return ""; // no reply yet
356 if (result < 0)
357 return "recv fail";
360 return 0; // success
363 bool CNetworkBase::PingHost(unsigned long ipaddr, unsigned short port, unsigned int timeOutMs, bool readability_check)
365 if (port == 0) // use icmp ping
366 return PingHost (ipaddr, timeOutMs);
368 struct sockaddr_in addr;
369 addr.sin_family = AF_INET;
370 addr.sin_port = htons(port);
371 addr.sin_addr.s_addr = ipaddr;
373 SOCKET soc = socket(AF_INET, SOCK_STREAM, 0);
375 const char* err_msg = "invalid socket";
377 if (soc != INVALID_SOCKET)
379 struct timeval tmout;
380 tmout.tv_sec = timeOutMs / 1000;
381 tmout.tv_usec = (timeOutMs % 1000) * 1000;
383 err_msg = ConnectHostPort (soc, addr, tmout, readability_check);
385 (void) closesocket (soc);
388 if (err_msg && *err_msg)
390 #ifdef TARGET_WINDOWS
391 std::string sock_err = CWIN32Util::WUSysMsg(WSAGetLastError());
392 #else
393 std::string sock_err = strerror(errno);
394 #endif
396 CLog::Log(LOGERROR, "{}({}:{}) - {} ({})", __FUNCTION__, inet_ntoa(addr.sin_addr), port,
397 err_msg, sock_err);
400 return err_msg == 0;
403 //creates, binds and listens tcp sockets on the desired port. Set bindLocal to
404 //true to bind to localhost only.
405 std::vector<SOCKET> CreateTCPServerSocket(const int port, const bool bindLocal, const int backlog, const char *callerName)
407 #ifdef WINSOCK_VERSION
408 int yes = 1;
409 #else
410 unsigned int yes = 1;
411 #endif
413 std::vector<SOCKET> sockets;
414 struct addrinfo* results = nullptr;
416 std::string sPort = std::to_string(port);
417 struct addrinfo hints = {};
418 hints.ai_family = PF_UNSPEC;
419 hints.ai_socktype = SOCK_STREAM;
420 hints.ai_flags = AI_PASSIVE;
421 hints.ai_protocol = 0;
423 int error = getaddrinfo(bindLocal ? "localhost" : nullptr, sPort.c_str(), &hints, &results);
424 if (error != 0)
425 return sockets;
427 for (struct addrinfo* result = results; result != nullptr; result = result->ai_next)
429 SOCKET sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
430 if (sock == INVALID_SOCKET)
431 continue;
433 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&yes), sizeof(yes));
434 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char*>(&yes), sizeof(yes));
436 if (bind(sock, result->ai_addr, result->ai_addrlen) != 0)
438 closesocket(sock);
439 CLog::Log(LOGDEBUG, "{} Server: Failed to bind {} serversocket", callerName,
440 result->ai_family == AF_INET6 ? "IPv6" : "IPv4");
441 continue;
444 if (listen(sock, backlog) == 0)
445 sockets.push_back(sock);
446 else
448 closesocket(sock);
449 CLog::Log(LOGERROR, "{} Server: Failed to set listen", callerName);
452 freeaddrinfo(results);
454 if (sockets.empty())
455 CLog::Log(LOGERROR, "{} Server: Failed to create serversocket(s)", callerName);
457 return sockets;
460 void CNetworkBase::WaitForNet()
462 const int timeout = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_POWERMANAGEMENT_WAITFORNETWORK);
463 if (timeout <= 0)
464 return; // wait for network is disabled
466 // check if we have at least one network interface to wait for
467 if (!IsAvailable())
468 return;
470 CLog::Log(LOGINFO, "{}: Waiting for a network interface to come up (Timeout: {} s)", __FUNCTION__,
471 timeout);
473 const static int intervalMs = 200;
474 const int numMaxTries = (timeout * 1000) / intervalMs;
476 for(int i=0; i < numMaxTries; ++i)
478 if (i > 0)
479 KODI::TIME::Sleep(std::chrono::milliseconds(intervalMs));
481 if (IsConnected())
483 CLog::Log(LOGINFO, "{}: A network interface is up after waiting {} ms", __FUNCTION__,
484 i * intervalMs);
485 return;
489 CLog::Log(LOGINFO, "{}: No network interface did come up within {} s... Giving up...",
490 __FUNCTION__, timeout);
493 std::string CNetworkBase::GetIpStr(const struct sockaddr* sa)
495 std::string result;
496 if (!sa)
497 return result;
499 char buffer[INET6_ADDRSTRLEN] = {};
500 switch (sa->sa_family)
502 case AF_INET:
503 inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in *>(sa)->sin_addr, buffer, INET_ADDRSTRLEN);
504 break;
505 case AF_INET6:
506 inet_ntop(AF_INET6, &reinterpret_cast<const struct sockaddr_in6 *>(sa)->sin6_addr, buffer, INET6_ADDRSTRLEN);
507 break;
508 default:
509 return result;
512 result = buffer;
513 return result;
516 std::string CNetworkBase::GetMaskByPrefixLength(uint8_t prefixLength)
518 if (prefixLength > 32)
519 return "";
521 struct sockaddr_in sa;
522 sa.sin_family = AF_INET;
523 sa.sin_addr.s_addr = htonl(~((1 << (32u - prefixLength)) - 1));;
524 return CNetworkBase::GetIpStr(reinterpret_cast<struct sockaddr*>(&sa));