2 * Copyright (C) 2016 Christian Browet
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.
9 #include "NetworkAndroid.h"
11 #include "utils/StringUtils.h"
12 #include "utils/log.h"
16 #include <androidjni/ConnectivityManager.h>
17 #include <androidjni/Context.h>
18 #include <androidjni/InetAddress.h>
19 #include <androidjni/LinkAddress.h>
20 #include <androidjni/NetworkInfo.h>
21 #include <androidjni/RouteInfo.h>
22 #include <arpa/inet.h>
23 #include <net/if_arp.h>
24 #include <netinet/in.h>
27 CNetworkInterfaceAndroid::CNetworkInterfaceAndroid(const CJNINetwork
& network
,
28 const CJNILinkProperties
& lp
,
29 const CJNINetworkInterface
& intf
)
30 : m_network(network
), m_lp(lp
), m_intf(intf
)
32 m_name
= m_intf
.getName();
35 std::vector
<std::string
> CNetworkInterfaceAndroid::GetNameServers()
37 std::vector
<std::string
> ret
;
39 CJNIList
<CJNIInetAddress
> lia
= m_lp
.getDnsServers();
40 ret
.reserve(lia
.size());
41 for (int i
=0; i
< lia
.size(); ++i
)
43 ret
.push_back(lia
.get(i
).getHostAddress());
49 bool CNetworkInterfaceAndroid::IsEnabled() const
51 CJNIConnectivityManager
connman(CJNIContext::getSystemService(CJNIContext::CONNECTIVITY_SERVICE
));
52 CJNINetworkInfo ni
= connman
.getNetworkInfo(m_network
);
56 return ni
.isAvailable();
59 bool CNetworkInterfaceAndroid::IsConnected() const
61 CJNIConnectivityManager
connman(CJNIContext::getSystemService(CJNIContext::CONNECTIVITY_SERVICE
));
62 CJNINetworkInfo ni
= connman
.getNetworkInfo(m_network
);
66 return ni
.isConnected();
69 std::string
CNetworkInterfaceAndroid::GetMacAddress() const
71 auto interfaceMacAddrRaw
= m_intf
.getHardwareAddress();
72 if (xbmc_jnienv()->ExceptionCheck())
74 xbmc_jnienv()->ExceptionClear();
75 CLog::Log(LOGERROR
, "CNetworkInterfaceAndroid::GetMacAddress Exception getting HW address");
78 if (interfaceMacAddrRaw
.size() >= 6)
80 return (StringUtils::Format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
81 (uint8_t)interfaceMacAddrRaw
[0], (uint8_t)interfaceMacAddrRaw
[1],
82 (uint8_t)interfaceMacAddrRaw
[2], (uint8_t)interfaceMacAddrRaw
[3],
83 (uint8_t)interfaceMacAddrRaw
[4], (uint8_t)interfaceMacAddrRaw
[5]));
88 void CNetworkInterfaceAndroid::GetMacAddressRaw(char rawMac
[6]) const
90 auto interfaceMacAddrRaw
= m_intf
.getHardwareAddress();
91 if (xbmc_jnienv()->ExceptionCheck())
93 xbmc_jnienv()->ExceptionClear();
94 CLog::Log(LOGERROR
, "CNetworkInterfaceAndroid::GetMacAddress Exception getting HW address");
97 if (interfaceMacAddrRaw
.size() >= 6)
98 memcpy(rawMac
, interfaceMacAddrRaw
.data(), 6);
101 bool CNetworkInterfaceAndroid::GetHostMacAddress(unsigned long host_ip
, std::string
& mac
) const
104 struct sockaddr_in
* sin
;
106 memset(&areq
, 0x0, sizeof(areq
));
108 sin
= (struct sockaddr_in
*) &areq
.arp_pa
;
109 sin
->sin_family
= AF_INET
;
110 sin
->sin_addr
.s_addr
= host_ip
;
112 sin
= (struct sockaddr_in
*) &areq
.arp_ha
;
113 sin
->sin_family
= ARPHRD_ETHER
;
115 strncpy(areq
.arp_dev
, m_name
.c_str(), sizeof(areq
.arp_dev
));
116 areq
.arp_dev
[sizeof(areq
.arp_dev
)-1] = '\0';
118 int sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
121 int result
= ioctl (sock
, SIOCGARP
, (caddr_t
) &areq
);
126 // CLog::Log(LOGERROR, "{} - GetHostMacAddress/ioctl failed with errno ({})", __FUNCTION__, errno);
133 struct sockaddr
* res
= &areq
.arp_ha
;
134 mac
= StringUtils::Format("{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", (uint8_t)res
->sa_data
[0],
135 (uint8_t)res
->sa_data
[1], (uint8_t)res
->sa_data
[2],
136 (uint8_t)res
->sa_data
[3], (uint8_t)res
->sa_data
[4],
137 (uint8_t)res
->sa_data
[5]);
139 for (int i
=0; i
<6; ++i
)
146 std::string
CNetworkInterfaceAndroid::GetCurrentIPAddress() const
148 CJNIList
<CJNILinkAddress
> lla
= m_lp
.getLinkAddresses();
153 for (;i
< lla
.size(); ++i
)
155 if (lla
.get(i
).getAddress().getAddress().size() > 4) // IPV4 only
162 CJNILinkAddress la
= lla
.get(i
);
163 return la
.getAddress().getHostAddress();
166 std::string
CNetworkInterfaceAndroid::GetCurrentNetmask() const
168 CJNIList
<CJNILinkAddress
> lla
= m_lp
.getLinkAddresses();
173 for (;i
< lla
.size(); ++i
)
175 if (lla
.get(i
).getAddress().getAddress().size() > 4) // IPV4 only
182 CJNILinkAddress la
= lla
.get(i
);
184 int prefix
= la
.getPrefixLength();
185 unsigned long mask
= (0xFFFFFFFF << (32 - prefix
)) & 0xFFFFFFFF;
186 return StringUtils::Format("{}.{}.{}.{}", mask
>> 24, (mask
>> 16) & 0xFF, (mask
>> 8) & 0xFF,
190 std::string
CNetworkInterfaceAndroid::GetCurrentDefaultGateway() const
192 CJNIList
<CJNIRouteInfo
> ris
= m_lp
.getRoutes();
194 for (int i
= 0; i
< ris
.size(); ++i
)
196 CJNIRouteInfo ri
= ris
.get(i
);
197 if (!ri
.isDefaultRoute())
200 return ri
.getGateway().getHostAddress();
206 std::string
CNetworkInterfaceAndroid::GetHostName()
208 CJNIList
<CJNILinkAddress
> lla
= m_lp
.getLinkAddresses();
213 for (;i
< lla
.size(); ++i
)
215 if (lla
.get(i
).getAddress().getAddress().size() > 4) // IPV4 only
222 CJNILinkAddress la
= lla
.get(i
);
223 return la
.getAddress().getHostName();
227 /*************************/
229 std::unique_ptr
<CNetworkBase
> CNetworkBase::GetNetwork()
231 return std::make_unique
<CNetworkAndroid
>();
234 CNetworkAndroid::CNetworkAndroid() : CNetworkBase(), CJNIXBMCConnectivityManagerNetworkCallback()
236 RetrieveInterfaces();
238 CJNIConnectivityManager connman
{CJNIContext::getSystemService(CJNIContext::CONNECTIVITY_SERVICE
)};
239 connman
.registerDefaultNetworkCallback(this->get_raw());
242 CNetworkAndroid::~CNetworkAndroid()
244 for (auto intf
: m_interfaces
)
246 for (auto intf
: m_oldInterfaces
)
249 CJNIConnectivityManager connman
{CJNIContext::getSystemService(CJNIContext::CONNECTIVITY_SERVICE
)};
250 connman
.unregisterNetworkCallback(this->get_raw());
253 bool CNetworkAndroid::GetHostName(std::string
& hostname
)
255 CNetworkInterfaceAndroid
* intf
= dynamic_cast<CNetworkInterfaceAndroid
*>(GetFirstConnectedInterface());
258 hostname
= intf
->GetHostName();
264 std::vector
<CNetworkInterface
*>& CNetworkAndroid::GetInterfaceList()
266 std::unique_lock
<CCriticalSection
> lock(m_refreshMutex
);
270 CNetworkInterface
* CNetworkAndroid::GetFirstConnectedInterface()
272 std::unique_lock
<CCriticalSection
> lock(m_refreshMutex
);
274 if (m_defaultInterface
)
275 return m_defaultInterface
.get();
278 for (CNetworkInterface
* intf
: m_interfaces
)
280 if (intf
->IsEnabled() && intf
->IsConnected() && !intf
->GetCurrentDefaultGateway().empty())
288 std::vector
<std::string
> CNetworkAndroid::GetNameServers()
290 CNetworkInterfaceAndroid
* intf
= static_cast<CNetworkInterfaceAndroid
*>(GetFirstConnectedInterface());
292 return intf
->GetNameServers();
294 return std::vector
<std::string
>();
297 bool CNetworkAndroid::PingHost(unsigned long remote_ip
, unsigned int timeout_ms
)
301 struct in_addr host_ip
;
302 host_ip
.s_addr
= remote_ip
;
304 snprintf(cmd_line
, sizeof(cmd_line
), "ping -c 1 -w %d %s",
305 timeout_ms
/ 1000 + (timeout_ms
% 1000) != 0, inet_ntoa(host_ip
));
307 int status
= system (cmd_line
);
309 int result
= WIFEXITED(status
) ? WEXITSTATUS(status
) : -1;
311 // http://linux.about.com/od/commands/l/blcmdl8_ping.htm ;
316 if (result
< 0 || result
> 1)
317 CLog::Log(LOGERROR
, "Ping fail : status = {}, errno = {} : '{}'", status
, errno
, cmd_line
);
322 void CNetworkAndroid::RetrieveInterfaces()
324 std::unique_lock
<CCriticalSection
> lock(m_refreshMutex
);
326 // Cannot delete interfaces here, as there still might have references to it
327 for (auto intf
: m_oldInterfaces
)
329 m_oldInterfaces
= m_interfaces
;
330 m_interfaces
.clear();
332 CJNIConnectivityManager
connman(CJNIContext::getSystemService(CJNIContext::CONNECTIVITY_SERVICE
));
333 std::vector
<CJNINetwork
> networks
= connman
.getAllNetworks();
335 for (const auto& n
: networks
)
337 CJNILinkProperties lp
= connman
.getLinkProperties(n
);
340 CJNINetworkInterface intf
= CJNINetworkInterface::getByName(lp
.getInterfaceName());
341 if (xbmc_jnienv()->ExceptionCheck())
343 xbmc_jnienv()->ExceptionClear();
344 CLog::Log(LOGERROR
, "CNetworkAndroid::RetrieveInterfaces Cannot get interface by name: {}",
345 lp
.getInterfaceName());
349 m_interfaces
.push_back(new CNetworkInterfaceAndroid(n
, lp
, intf
));
351 CLog::Log(LOGERROR
, "CNetworkAndroid::RetrieveInterfaces Cannot get interface by name: {}",
352 lp
.getInterfaceName());
356 "CNetworkAndroid::RetrieveInterfaces Cannot get link properties for network: {}",
361 void CNetworkAndroid::onAvailable(const CJNINetwork n
)
363 CLog::Log(LOGDEBUG
, "CNetworkAndroid::onAvailable The default network is now: {}", n
.toString());
365 CJNIConnectivityManager connman
{CJNIContext::getSystemService(CJNIContext::CONNECTIVITY_SERVICE
)};
366 CJNILinkProperties lp
= connman
.getLinkProperties(n
);
370 CJNINetworkInterface intf
= CJNINetworkInterface::getByName(lp
.getInterfaceName());
372 m_defaultInterface
= std::make_unique
<CNetworkInterfaceAndroid
>(n
, lp
, intf
);
376 void CNetworkAndroid::onLost(const CJNINetwork n
)
378 CLog::Log(LOGDEBUG
, "CNetworkAndroid::onLost No default network (the last was: {})",
380 m_defaultInterface
= nullptr;