Fixes for the network reachaiblity monitor
This commit is contained in:
parent
e6b79e2a44
commit
9c4ba63556
@ -8,7 +8,8 @@ Q_DECLARE_LOGGING_CATEGORY(dcNymeaConnection)
|
||||
NetworkReachabilityMonitor::NetworkReachabilityMonitor(QObject *parent)
|
||||
: QObject{parent}
|
||||
{
|
||||
|
||||
// NOTE: The Qt API is not working at all on iOS, we're using the iOS reachability API instead.
|
||||
// See iOS implementation in .mm file
|
||||
#if defined(Q_OS_IOS)
|
||||
setupIOS();
|
||||
#endif
|
||||
@ -51,7 +52,6 @@ NymeaConnection::BearerTypes NetworkReachabilityMonitor::availableBearerTypes()
|
||||
|
||||
void NetworkReachabilityMonitor::updateActiveBearers()
|
||||
{
|
||||
// NOTE: The Qt API is not working at all on iOS, we're using the iOS reachability API instead.
|
||||
#if defined(Q_OS_IOS)
|
||||
return;
|
||||
#endif
|
||||
@ -61,6 +61,7 @@ void NetworkReachabilityMonitor::updateActiveBearers()
|
||||
qCDebug(dcNymeaConnection()) << "Network configuations:" << configs.count();
|
||||
foreach (const QNetworkConfiguration &config, configs) {
|
||||
qCDebug(dcNymeaConnection()) << "Active network config:" << config.name() << config.bearerTypeFamily() << config.bearerTypeName();
|
||||
availableBearerTypes.setFlag(qBearerTypeToNymeaBearerType(config.bearerType()));
|
||||
}
|
||||
if (availableBearerTypes == NymeaConnection::BearerTypeNone) {
|
||||
// This is just debug info... On some platform bearer management seems a bit broken, so let's get some infos right away...
|
||||
|
||||
@ -36,8 +36,8 @@ private:
|
||||
#ifdef Q_OS_IOS
|
||||
void setupIOS();
|
||||
void teardownIOS();
|
||||
SCNetworkReachabilityRef m_reachabilityRef;
|
||||
static NymeaConnection::BearerType flagsToBearerType(SCNetworkReachabilityFlags flags);
|
||||
SCNetworkReachabilityRef m_internetReachabilityRef = nullptr;
|
||||
SCNetworkReachabilityRef m_lanReachabilityRef = nullptr;
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info);
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -15,87 +15,105 @@ Q_DECLARE_LOGGING_CATEGORY(dcNymeaConnection)
|
||||
|
||||
void NetworkReachabilityMonitor::ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
|
||||
{
|
||||
#pragma unused (target, flags)
|
||||
NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
|
||||
|
||||
NetworkReachabilityMonitor* thiz = (__bridge NetworkReachabilityMonitor *)info;
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
NymeaConnection::BearerTypes old = thiz->m_availableBearerTypes;
|
||||
thiz->m_availableBearerTypes = flagsToBearerType(flags);
|
||||
qCDebug(dcNymeaConnection()) << "Network reachability changed. Old bearers:" << old << "New bearers:" << thiz->m_availableBearerTypes << "(Flags:" << flags << ")";
|
||||
if (thiz->m_availableBearerTypes != old) {
|
||||
|
||||
NymeaConnection::BearerTypes newTypes = thiz->m_availableBearerTypes;
|
||||
|
||||
if (target == thiz->m_internetReachabilityRef) {
|
||||
// If the internet reachability changes, enable the mobile data bearer if we're reaching the internet through mobile data
|
||||
newTypes.setFlag(NymeaConnection::BearerTypeMobileData, (flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsWWAN));
|
||||
qCDebug(dcNymeaConnection()) << "Internet reachability changed";
|
||||
} else if (target == thiz->m_lanReachabilityRef) {
|
||||
// If the lan reachability changes, we'll enable the wifi bearer, regardless of how
|
||||
newTypes.setFlag(NymeaConnection::BearerTypeWiFi, flags & kSCNetworkReachabilityFlagsReachable);
|
||||
qCDebug(dcNymeaConnection()) << "LAN reachability changed";
|
||||
}
|
||||
|
||||
qCDebug(dcNymeaConnection()) << "Old bearers:" << thiz->m_availableBearerTypes << QString("new network reachability flags: %1%2 %3%4%5%6%7%8%9")
|
||||
.arg((flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-')
|
||||
|
||||
.arg((flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-')
|
||||
.arg((flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-')
|
||||
<< "new bearers:" << newTypes;
|
||||
|
||||
if (thiz->m_availableBearerTypes != newTypes) {
|
||||
thiz->m_availableBearerTypes = newTypes;
|
||||
emit thiz->availableBearerTypesChanged();
|
||||
}
|
||||
emit thiz->availableBearerTypesUpdated();
|
||||
|
||||
}
|
||||
|
||||
void NetworkReachabilityMonitor::setupIOS()
|
||||
{
|
||||
SCNetworkReachabilityContext context = {0, (__bridge void *)(this), NULL, NULL, NULL};
|
||||
|
||||
struct sockaddr_in zeroAddress;
|
||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||
zeroAddress.sin_family = AF_INET;
|
||||
|
||||
m_reachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress);
|
||||
if (m_reachabilityRef == NULL) {
|
||||
qCCritical(dcNymeaConnection()) << "Error setting up reachability monitor";
|
||||
return;
|
||||
}
|
||||
m_internetReachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress);
|
||||
|
||||
SCNetworkReachabilityContext context = {0, (__bridge void *)(this), NULL, NULL, NULL};
|
||||
if (SCNetworkReachabilitySetCallback(m_reachabilityRef, ReachabilityCallback, &context)) {
|
||||
if (SCNetworkReachabilityScheduleWithRunLoop(m_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
} else {
|
||||
qCCritical(dcNymeaConnection()) << "Error setting up reachability callback";
|
||||
if (m_internetReachabilityRef) {
|
||||
if (SCNetworkReachabilitySetCallback(m_internetReachabilityRef, ReachabilityCallback, &context)) {
|
||||
if (SCNetworkReachabilityScheduleWithRunLoop(m_internetReachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
} else {
|
||||
qCCritical(dcNymeaConnection()) << "Error setting up internet reachability callback (runloop)";
|
||||
}
|
||||
}
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(m_internetReachabilityRef, &flags)) {
|
||||
m_availableBearerTypes.setFlag(NymeaConnection::BearerTypeMobileData, (flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsWWAN));
|
||||
}
|
||||
} else {
|
||||
qCCritical(dcNymeaConnection()) << "Error setting up internet reachability monitor (register)";
|
||||
}
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(m_reachabilityRef, &flags)) {
|
||||
m_availableBearerTypes = flagsToBearerType(flags);
|
||||
|
||||
struct sockaddr_in linkLocalAddress;
|
||||
bzero(&linkLocalAddress, sizeof(linkLocalAddress));
|
||||
linkLocalAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
|
||||
linkLocalAddress.sin_len = sizeof(linkLocalAddress);
|
||||
linkLocalAddress.sin_family = AF_INET;
|
||||
|
||||
m_lanReachabilityRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&linkLocalAddress);
|
||||
|
||||
if (m_lanReachabilityRef) {
|
||||
if (SCNetworkReachabilitySetCallback(m_lanReachabilityRef, ReachabilityCallback, &context)) {
|
||||
if (SCNetworkReachabilityScheduleWithRunLoop(m_lanReachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
} else {
|
||||
qCCritical(dcNymeaConnection()) << "Error setting up LAN reachability callback (runloop)";
|
||||
}
|
||||
}
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(m_lanReachabilityRef, &flags)) {
|
||||
m_availableBearerTypes.setFlag(NymeaConnection::BearerTypeWiFi, flags & kSCNetworkReachabilityFlagsReachable);
|
||||
}
|
||||
} else {
|
||||
qCCritical(dcNymeaConnection()) << "Error setting up LAN reachability monitor (register)";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NetworkReachabilityMonitor::teardownIOS()
|
||||
{
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(m_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
|
||||
NymeaConnection::BearerType NetworkReachabilityMonitor::flagsToBearerType(SCNetworkReachabilityFlags flags)
|
||||
{
|
||||
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
|
||||
return NymeaConnection::BearerTypeNone;
|
||||
}
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) {
|
||||
/*
|
||||
If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
|
||||
*/
|
||||
return NymeaConnection::BearerTypeWiFi;
|
||||
}
|
||||
|
||||
if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) {
|
||||
/*
|
||||
... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
|
||||
*/
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
|
||||
{
|
||||
/*
|
||||
... and no [user] intervention is needed...
|
||||
*/
|
||||
return NymeaConnection::BearerTypeWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
/*
|
||||
... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
|
||||
*/
|
||||
return NymeaConnection::BearerTypeMobileData;
|
||||
}
|
||||
|
||||
return NymeaConnection::BearerTypeNone;
|
||||
if (m_internetReachabilityRef) {
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(m_internetReachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
CFRelease(m_internetReachabilityRef);
|
||||
m_internetReachabilityRef = nullptr;
|
||||
}
|
||||
if (m_lanReachabilityRef) {
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(m_lanReachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
CFRelease(m_lanReachabilityRef);
|
||||
m_lanReachabilityRef = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user