summaryrefslogtreecommitdiffstats
path: root/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
blob: 0b45eb9ce31f4a51eaa6e65a6fe177d576372b10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright (C) 2021 Ilya Fedin <fedin-ilja2010@ya.ru>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include <QtNetwork/private/qnetworkinformation_p.h>

#include <QtCore/qglobal.h>
#include <QtCore/private/qobject_p.h>

#include <gio/gio.h>

QT_BEGIN_NAMESPACE

using namespace Qt::StringLiterals;

Q_DECLARE_LOGGING_CATEGORY(lcNetInfoGlib)
Q_LOGGING_CATEGORY(lcNetInfoGlib, "qt.network.info.glib");

namespace {
QNetworkInformation::Reachability reachabilityFromGNetworkConnectivity(GNetworkConnectivity connectivity)
{
    switch (connectivity) {
    case G_NETWORK_CONNECTIVITY_LOCAL:
        return QNetworkInformation::Reachability::Disconnected;
    case G_NETWORK_CONNECTIVITY_LIMITED:
    case G_NETWORK_CONNECTIVITY_PORTAL:
        return QNetworkInformation::Reachability::Site;
    case G_NETWORK_CONNECTIVITY_FULL:
        return QNetworkInformation::Reachability::Online;
    }
    return QNetworkInformation::Reachability::Unknown;
}
}

static QString backendName = QStringLiteral("glib");

class QGlibNetworkInformationBackend : public QNetworkInformationBackend
{
    Q_OBJECT
public:
    QGlibNetworkInformationBackend();
    ~QGlibNetworkInformationBackend();

    QString name() const override { return backendName; }
    QNetworkInformation::Features featuresSupported() const override
    {
        if (!isValid())
            return {};
        return featuresSupportedStatic();
    }

    static QNetworkInformation::Features featuresSupportedStatic()
    {
        using Feature = QNetworkInformation::Feature;
        return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
                                             | Feature::Metered);
    }

    bool isValid() const;

private:
    Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackend)

    static void updateConnectivity(QGlibNetworkInformationBackend *backend);
    static void updateMetered(QGlibNetworkInformationBackend *backend);

    GNetworkMonitor *networkMonitor = nullptr;
    gulong connectivityHandlerId = 0;
    gulong meteredHandlerId = 0;
};

class QGlibNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID QNetworkInformationBackendFactory_iid)
    Q_INTERFACES(QNetworkInformationBackendFactory)
public:
    QGlibNetworkInformationBackendFactory() = default;
    ~QGlibNetworkInformationBackendFactory() = default;
    QString name() const override { return backendName; }
    QNetworkInformation::Features featuresSupported() const override
    {
        return QGlibNetworkInformationBackend::featuresSupportedStatic();
    }

    QNetworkInformationBackend *create(QNetworkInformation::Features requiredFeatures) const override
    {
        if ((requiredFeatures & featuresSupported()) != requiredFeatures)
            return nullptr;
        auto backend = new QGlibNetworkInformationBackend();
        if (!backend->isValid())
            delete std::exchange(backend, nullptr);
        return backend;
    }
private:
    Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackendFactory)
};

QGlibNetworkInformationBackend::QGlibNetworkInformationBackend()
: networkMonitor(g_network_monitor_get_default())
{
    updateConnectivity(this);
    updateMetered(this);

    connectivityHandlerId = g_signal_connect_swapped(networkMonitor, "notify::connectivity",
                                                     G_CALLBACK(updateConnectivity), this);

    meteredHandlerId = g_signal_connect_swapped(networkMonitor, "notify::network-metered",
                                                G_CALLBACK(updateMetered), this);
}

QGlibNetworkInformationBackend::~QGlibNetworkInformationBackend()
{
    g_signal_handler_disconnect(networkMonitor, meteredHandlerId);
    g_signal_handler_disconnect(networkMonitor, connectivityHandlerId);
}

bool QGlibNetworkInformationBackend::isValid() const
{
    return QLatin1StringView(G_OBJECT_TYPE_NAME(networkMonitor)) != "GNetworkMonitorBase"_L1;
}

void QGlibNetworkInformationBackend::updateConnectivity(QGlibNetworkInformationBackend *backend)
{
    const auto connectivityState = g_network_monitor_get_connectivity(backend->networkMonitor);
    const bool behindPortal = (connectivityState == G_NETWORK_CONNECTIVITY_PORTAL);
    backend->setReachability(reachabilityFromGNetworkConnectivity(connectivityState));
    backend->setBehindCaptivePortal(behindPortal);
}

void QGlibNetworkInformationBackend::updateMetered(QGlibNetworkInformationBackend *backend)
{
    backend->setMetered(g_network_monitor_get_network_metered(backend->networkMonitor));
}

QT_END_NAMESPACE

#include "qglibnetworkinformationbackend.moc"