Skip to content

Commit d035fb6

Browse files
committed
Notify connecting/disconnecting state from vpn connection on Win
fix brave/brave-browser#17883
1 parent 5d29af1 commit d035fb6

File tree

4 files changed

+128
-17
lines changed

4 files changed

+128
-17
lines changed

components/brave_vpn/brave_vpn_os_connection_api_win.cc

+50-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
// ([email protected])'s work (https://github.com/bsclifton/winvpntool).
1818

1919
using brave_vpn::internal::CheckConnectionResult;
20+
using brave_vpn::internal::CloseEventHandleForConnecting;
2021
using brave_vpn::internal::CreateEntry;
22+
using brave_vpn::internal::GetEventHandleForConnecting;
2123
using brave_vpn::internal::GetPhonebookPath;
2224
using brave_vpn::internal::PrintRasError;
2325
using brave_vpn::internal::RemoveEntry;
@@ -47,7 +49,9 @@ BraveVPNOSConnectionAPIWin::BraveVPNOSConnectionAPIWin() {
4749
}
4850

4951
BraveVPNOSConnectionAPIWin::~BraveVPNOSConnectionAPIWin() {
50-
CloseHandle(event_handle_);
52+
CloseHandle(event_handle_for_connected_);
53+
CloseHandle(event_handle_for_disconnected_);
54+
CloseEventHandleForConnecting();
5155
}
5256

5357
void BraveVPNOSConnectionAPIWin::CreateVPNConnection(
@@ -75,6 +79,10 @@ void BraveVPNOSConnectionAPIWin::Connect(const std::string& name) {
7579
}
7680

7781
void BraveVPNOSConnectionAPIWin::Disconnect(const std::string& name) {
82+
// Fire pseudo disconnecting noti because windows doesn't have it.
83+
for (Observer& obs : observers_)
84+
obs.OnIsDisconnecting(name);
85+
7886
// Connection state update from this call will be done by monitoring.
7987
base::ThreadPool::PostTask(
8088
FROM_HERE, {base::MayBlock()},
@@ -100,7 +108,18 @@ void BraveVPNOSConnectionAPIWin::CheckConnection(const std::string& name) {
100108
void BraveVPNOSConnectionAPIWin::OnObjectSignaled(HANDLE object) {
101109
DCHECK(!target_vpn_entry_name().empty());
102110

103-
CheckConnection(target_vpn_entry_name());
111+
CheckConnectionResult result = CheckConnectionResult::UNKNOWN;
112+
if (object == GetEventHandleForConnecting()) {
113+
result = CheckConnectionResult::CONNECTING;
114+
} else if (object == event_handle_for_connected_) {
115+
result = CheckConnectionResult::CONNECTED;
116+
} else if (object == event_handle_for_disconnected_) {
117+
result = CheckConnectionResult::DISCONNECTED;
118+
} else {
119+
NOTREACHED();
120+
}
121+
122+
OnCheckConnection(target_vpn_entry_name(), result);
104123
}
105124

106125
void BraveVPNOSConnectionAPIWin::OnCheckConnection(
@@ -109,9 +128,20 @@ void BraveVPNOSConnectionAPIWin::OnCheckConnection(
109128
if (result == CheckConnectionResult::UNKNOWN)
110129
return;
111130

112-
const bool connected = result == CheckConnectionResult::CONNECTED;
113131
for (Observer& obs : observers_) {
114-
connected ? obs.OnConnected(name) : obs.OnDisconnected(name);
132+
switch (result) {
133+
case CheckConnectionResult::CONNECTED:
134+
obs.OnConnected(name);
135+
break;
136+
case CheckConnectionResult::CONNECTING:
137+
obs.OnIsConnecting(name);
138+
break;
139+
case CheckConnectionResult::DISCONNECTED:
140+
obs.OnDisconnected(name);
141+
break;
142+
default:
143+
break;
144+
}
115145
}
116146
}
117147

@@ -134,13 +164,24 @@ void BraveVPNOSConnectionAPIWin::OnRemoved(const std::string& name,
134164
}
135165

136166
void BraveVPNOSConnectionAPIWin::StartVPNConnectionChangeMonitoring() {
137-
DCHECK(!event_handle_);
138-
event_handle_ = CreateEvent(nullptr, false, false, nullptr);
167+
DCHECK(!event_handle_for_connected_ && !event_handle_for_disconnected_);
168+
169+
event_handle_for_connected_ = CreateEvent(nullptr, false, false, nullptr);
170+
event_handle_for_disconnected_ = CreateEvent(nullptr, false, false, nullptr);
139171

172+
// We don't need to check current connection state again if monitor each event
173+
// separately.
174+
RasConnectionNotificationW(static_cast<HRASCONN>(INVALID_HANDLE_VALUE),
175+
event_handle_for_connected_, RASCN_Connection);
140176
RasConnectionNotificationW(static_cast<HRASCONN>(INVALID_HANDLE_VALUE),
141-
event_handle_,
142-
(RASCN_Connection | RASCN_Disconnection));
143-
watcher_.StartWatchingMultipleTimes(event_handle_, this);
177+
event_handle_for_disconnected_,
178+
RASCN_Disconnection);
179+
connected_event_watcher_.StartWatchingMultipleTimes(
180+
event_handle_for_connected_, this);
181+
disconnected_event_watcher_.StartWatchingMultipleTimes(
182+
event_handle_for_disconnected_, this);
183+
connecting_event_watcher_.StartWatchingMultipleTimes(
184+
GetEventHandleForConnecting(), this);
144185
}
145186

146187
} // namespace brave_vpn

components/brave_vpn/brave_vpn_os_connection_api_win.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,11 @@ class BraveVPNOSConnectionAPIWin : public BraveVPNOSConnectionAPI,
5151

5252
void StartVPNConnectionChangeMonitoring();
5353

54-
HANDLE event_handle_ = nullptr;
55-
base::win::ObjectWatcher watcher_;
54+
HANDLE event_handle_for_connected_ = nullptr;
55+
HANDLE event_handle_for_disconnected_ = nullptr;
56+
base::win::ObjectWatcher connected_event_watcher_;
57+
base::win::ObjectWatcher connecting_event_watcher_;
58+
base::win::ObjectWatcher disconnected_event_watcher_;
5659
base::WeakPtrFactory<BraveVPNOSConnectionAPIWin> weak_factory_{this};
5760
};
5861

components/brave_vpn/utils_win.cc

+68-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@ namespace brave_vpn {
1818

1919
namespace {
2020

21+
HANDLE g_event_handle = nullptr;
22+
23+
void WINAPI RasDialFunc(UINT, RASCONNSTATE rasconnstate, DWORD error) {
24+
if (error) {
25+
internal::PrintRasError(error);
26+
return;
27+
}
28+
29+
// Only interested in connecting event.
30+
switch (rasconnstate) {
31+
case RASCS_ConnectDevice:
32+
SetEvent(g_event_handle);
33+
break;
34+
default:
35+
// Ignore all other states.
36+
break;
37+
}
38+
}
39+
2140
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessage
2241
void PrintSystemError(DWORD error) {
2342
constexpr DWORD kBufSize = 512;
@@ -57,6 +76,19 @@ DWORD SetCredentials(LPCTSTR entry_name, LPCTSTR username, LPCTSTR password) {
5776

5877
namespace internal {
5978

79+
HANDLE GetEventHandleForConnecting() {
80+
if (!g_event_handle)
81+
g_event_handle = CreateEvent(nullptr, false, false, nullptr);
82+
return g_event_handle;
83+
}
84+
85+
void CloseEventHandleForConnecting() {
86+
if (g_event_handle) {
87+
CloseHandle(g_event_handle);
88+
g_event_handle = nullptr;
89+
}
90+
}
91+
6092
// https://docs.microsoft.com/en-us/windows/win32/api/ras/nf-ras-rasgeterrorstringa
6193
void PrintRasError(DWORD error) {
6294
constexpr DWORD kBufSize = 512;
@@ -197,8 +229,8 @@ bool ConnectEntry(const std::wstring& entry_name) {
197229

198230
DVLOG(2) << "Connecting to " << entry_name;
199231
HRASCONN h_ras_conn = NULL;
200-
dw_ret = RasDial(NULL, DEFAULT_PHONE_BOOK, lp_ras_dial_params, NULL, NULL,
201-
&h_ras_conn);
232+
dw_ret = RasDial(NULL, DEFAULT_PHONE_BOOK, lp_ras_dial_params, 0,
233+
(LPVOID)(&RasDialFunc), &h_ras_conn);
202234
if (dw_ret != ERROR_SUCCESS) {
203235
HeapFree(GetProcessHeap(), 0, (LPVOID)lp_ras_dial_params);
204236
PrintRasError(dw_ret);
@@ -324,6 +356,37 @@ bool CreateEntry(const std::wstring& entry_name,
324356
return true;
325357
}
326358

359+
CheckConnectionResult GetConnectionState(HRASCONN h_ras_conn) {
360+
DWORD dw_ret = 0;
361+
362+
RASCONNSTATUS ras_conn_status;
363+
ZeroMemory(&ras_conn_status, sizeof(RASCONNSTATUS));
364+
ras_conn_status.dwSize = sizeof(RASCONNSTATUS);
365+
366+
// Checking connection status using RasGetConnectStatus
367+
dw_ret = RasGetConnectStatus(h_ras_conn, &ras_conn_status);
368+
if (ERROR_SUCCESS != dw_ret) {
369+
LOG(ERROR) << "RasGetConnectStatus failed: Error = " << dw_ret;
370+
return CheckConnectionResult::UNKNOWN;
371+
}
372+
373+
switch (ras_conn_status.rasconnstate) {
374+
case RASCS_ConnectDevice:
375+
VLOG(2) << "Connecting device...";
376+
return CheckConnectionResult::CONNECTING;
377+
case RASCS_Connected:
378+
VLOG(2) << "Connection completed";
379+
return CheckConnectionResult::CONNECTED;
380+
case RASCS_Disconnected:
381+
VLOG(2) << "Disconnected";
382+
return CheckConnectionResult::DISCONNECTED;
383+
default:
384+
break;
385+
}
386+
387+
return CheckConnectionResult::DISCONNECTED;
388+
}
389+
327390
CheckConnectionResult CheckConnection(const std::wstring& entry_name) {
328391
if (entry_name.empty())
329392
return CheckConnectionResult::UNKNOWN;
@@ -339,7 +402,7 @@ CheckConnectionResult CheckConnection(const std::wstring& entry_name) {
339402

340403
// If got success here, it means there is no connected vpn entry.
341404
if (dw_ret == ERROR_SUCCESS) {
342-
return CheckConnectionResult::NOT_CONNECTED;
405+
return CheckConnectionResult::DISCONNECTED;
343406
}
344407

345408
// Abnormal situation.
@@ -367,10 +430,10 @@ CheckConnectionResult CheckConnection(const std::wstring& entry_name) {
367430
}
368431

369432
// If successful, find connection with |entry_name|.
370-
CheckConnectionResult result = CheckConnectionResult::NOT_CONNECTED;
433+
CheckConnectionResult result = CheckConnectionResult::DISCONNECTED;
371434
for (DWORD i = 0; i < dw_connections; i++) {
372435
if (entry_name.compare(lp_ras_conn[i].szEntryName) == 0) {
373-
result = CheckConnectionResult::CONNECTED;
436+
result = GetConnectionState(lp_ras_conn[i].hrasconn);
374437
break;
375438
}
376439
}

components/brave_vpn/utils_win.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ namespace internal {
1515

1616
enum class CheckConnectionResult {
1717
CONNECTED,
18-
NOT_CONNECTED,
18+
CONNECTING,
19+
DISCONNECTED,
1920
UNKNOWN,
2021
};
2122

@@ -29,6 +30,9 @@ bool CreateEntry(const std::wstring& entry_name,
2930
bool RemoveEntry(const std::wstring& entry_name);
3031
bool DisconnectEntry(const std::wstring& entry_name);
3132
bool ConnectEntry(const std::wstring& entry_name);
33+
// Don't cache returned HANDLE. It could be invalidated.
34+
HANDLE GetEventHandleForConnecting();
35+
void CloseEventHandleForConnecting();
3236

3337
CheckConnectionResult CheckConnection(const std::wstring& entry_name);
3438

0 commit comments

Comments
 (0)