blob: 0446223d4cddc4304c774f40160e47ee854e8b41 [file] [log] [blame]
Sébastien Blin1f915762020-08-03 13:27:42 -04001/*
2 * Copyright (C) 2019-2020 by Savoir-faire Linux
3 * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "connectivitymonitor.h"
20
21#include <QDebug>
22
23#ifdef Q_OS_WIN
24#include <atlbase.h>
25#include <netlistmgr.h>
26
27class NetworkEventHandler : public INetworkListManagerEvents
28{
29public:
30 NetworkEventHandler()
31 : m_lRefCnt(1){};
32 virtual ~NetworkEventHandler(){};
33
34 HRESULT STDMETHODCALLTYPE
35 QueryInterface(REFIID riid, void **ppvObject)
36 {
37 HRESULT hr = S_OK;
38 if (IsEqualIID(riid, IID_IUnknown)) {
39 *ppvObject = (IUnknown *) this;
40 } else if (IsEqualIID(riid, IID_INetworkListManagerEvents)) {
41 *ppvObject = (INetworkListManagerEvents *) this;
42 } else {
43 hr = E_NOINTERFACE;
44 }
45
46 return hr;
47 };
48 ULONG STDMETHODCALLTYPE
49 AddRef()
50 {
51 return (ULONG) InterlockedIncrement(&m_lRefCnt);
52 };
53 ULONG STDMETHODCALLTYPE
54 Release()
55 {
56 LONG res = InterlockedDecrement(&m_lRefCnt);
57 if (res == 0) {
58 delete this;
59 }
60 return (ULONG) res;
61 };
62
63 virtual HRESULT STDMETHODCALLTYPE
64 ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
65 {
66 qDebug() << "connectivity changed: " << newConnectivity;
67 if (connectivityChangedCb_) {
68 connectivityChangedCb_();
69 }
70 return S_OK;
71 };
72
73 void
74 setOnConnectivityChangedCallBack(std::function<void()> &&cb)
75 {
76 connectivityChangedCb_ = cb;
77 };
78
79private:
80 LONG m_lRefCnt;
81
82 std::function<void()> connectivityChangedCb_;
83};
84
85ConnectivityMonitor::ConnectivityMonitor(QObject *parent)
86 : QObject(parent)
87{
88 CoInitialize(NULL);
89
90 IUnknown *pUnknown = NULL;
91
92 HRESULT hr = CoCreateInstance(CLSID_NetworkListManager,
93 NULL,
94 CLSCTX_ALL,
95 IID_IUnknown,
96 (void **) &pUnknown);
97 if (FAILED(hr)) {
98 return;
99 }
100
101 pNetworkListManager_ = NULL;
102 hr = pUnknown->QueryInterface(IID_INetworkListManager, (void **) &pNetworkListManager_);
103 if (FAILED(hr)) {
104 destroy();
105 pUnknown->Release();
106 return;
107 }
108
109 pCPContainer_ = NULL;
110 hr = pNetworkListManager_->QueryInterface(IID_IConnectionPointContainer,
111 (void **) &pCPContainer_);
112 if (FAILED(hr)) {
113 destroy();
114 pUnknown->Release();
115 return;
116 }
117
118 pConnectPoint_ = NULL;
119 hr = pCPContainer_->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint_);
120 if (SUCCEEDED(hr)) {
121 cookie_ = NULL;
122 netEventHandler_ = new NetworkEventHandler;
123 netEventHandler_->setOnConnectivityChangedCallBack([this] { emit connectivityChanged(); });
124 hr = pConnectPoint_->Advise((IUnknown *) netEventHandler_, &cookie_);
125 } else {
126 destroy();
127 }
128
129 pUnknown->Release();
130}
131
132bool
133ConnectivityMonitor::isOnline()
134{
135 if (!pNetworkListManager_) {
136 return false;
137 }
138 VARIANT_BOOL IsConnect = VARIANT_FALSE;
139 HRESULT hr = pNetworkListManager_->get_IsConnectedToInternet(&IsConnect);
140 if (SUCCEEDED(hr)) {
141 return IsConnect == VARIANT_TRUE;
142 }
143 return false;
144}
145
146void
147ConnectivityMonitor::destroy()
148{
149 if (pConnectPoint_) {
150 pConnectPoint_->Unadvise(cookie_);
151 pConnectPoint_->Release();
152 }
153 if (pCPContainer_) {
154 pCPContainer_->Release();
155 }
156 if (pNetworkListManager_) {
157 pNetworkListManager_->Release();
158 pNetworkListManager_ = NULL;
159 }
160}
161
162ConnectivityMonitor::~ConnectivityMonitor()
163{
164 destroy();
165 CoUninitialize();
166}
167#endif // Q_OS_WIN