Skip to content

Commit 0d6f012

Browse files
committed
v2.19.2
1 parent 7a7cf5f commit 0d6f012

File tree

149 files changed

+9349
-1976
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+9349
-1976
lines changed

libs/wsnet/src/dnsresolver/dnsresolver_cares.cpp

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
#include <netinet/in.h>
1212
#include <arpa/inet.h>
1313
#include <netdb.h>
14-
#include <sys/select.h>
14+
#include <poll.h>
15+
#elif defined(_WIN32) || defined(_WIN64)
16+
#include <winsock2.h>
17+
#define poll WSAPoll
1518
#endif
1619

1720
#if defined(__APPLE__) && !defined(IS_MOBILE_PLATFORM)
@@ -129,7 +132,15 @@ void DnsResolver_cares::run()
129132
std::queue<QueueItem> localQueue;
130133
while (!finish_) {
131134

132-
{ // mutex lock section
135+
// Check if c-ares still has active sockets
136+
// If so, do not block so that the next batch can be processed immediately
137+
ares_socket_t temp_sockets[ARES_GETSOCK_MAXNUM];
138+
int temp_bitmask = ares_getsock(channel, temp_sockets, ARES_GETSOCK_MAXNUM);
139+
bool has_active_sockets = (temp_bitmask != 0);
140+
141+
// Wait only if there are no active requests and no active sockets
142+
if (!has_active_sockets) {
143+
// mutex lock section
133144
std::unique_lock<std::mutex> locker(mutex_);
134145
condition_.wait(locker, [this]{ return !activeRequests_.empty() || finish_; });
135146
localQueue = queue_;
@@ -178,17 +189,56 @@ void DnsResolver_cares::run()
178189
}
179190

180191
// process
181-
fd_set readers, writers;
182-
FD_ZERO(&readers);
183-
FD_ZERO(&writers);
184-
int nfds = ares_fds(channel, &readers, &writers);
185-
if (nfds != 0) {
192+
ares_socket_t sockets[ARES_GETSOCK_MAXNUM];
193+
int bitmask = ares_getsock(channel, sockets, ARES_GETSOCK_MAXNUM);
194+
195+
struct pollfd pfds[ARES_GETSOCK_MAXNUM];
196+
int nfds = 0;
197+
198+
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
199+
if (ARES_GETSOCK_READABLE(bitmask, i) || ARES_GETSOCK_WRITABLE(bitmask, i)) {
200+
pfds[nfds].fd = sockets[i];
201+
pfds[nfds].events = 0;
202+
pfds[nfds].revents = 0;
203+
204+
if (ARES_GETSOCK_READABLE(bitmask, i)) {
205+
pfds[nfds].events |= POLLIN;
206+
}
207+
if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
208+
pfds[nfds].events |= POLLOUT;
209+
}
210+
nfds++;
211+
}
212+
}
213+
214+
if (nfds > 0) {
186215
// do not block for longer than kTimeoutMs interval
187-
timeval tvp;
188-
tvp.tv_sec = 0;
189-
tvp.tv_usec = kTimeoutMs * 1000;
190-
select(nfds, &readers, &writers, NULL, &tvp);
191-
ares_process(channel, &readers, &writers);
216+
int timeout_ms = kTimeoutMs;
217+
poll(pfds, nfds, timeout_ms);
218+
219+
// Convert poll events to ares_fd_events_t for ares_process_fds
220+
ares_fd_events_t events[ARES_GETSOCK_MAXNUM];
221+
int nevents = 0;
222+
223+
for (int i = 0; i < nfds; i++) {
224+
events[nevents].fd = pfds[i].fd;
225+
events[nevents].events = 0;
226+
227+
if (pfds[i].revents & POLLIN) {
228+
events[nevents].events |= ARES_FD_EVENT_READ;
229+
}
230+
if (pfds[i].revents & POLLOUT) {
231+
events[nevents].events |= ARES_FD_EVENT_WRITE;
232+
}
233+
234+
// Include the fd even if no events (for timeout processing)
235+
nevents++;
236+
}
237+
238+
ares_process_fds(channel, events, nevents, ARES_PROCESS_FLAG_NONE);
239+
} else {
240+
// No file descriptors to process, but still need to handle timeouts
241+
ares_process_fds(channel, NULL, 0, ARES_PROCESS_FLAG_NONE);
192242
}
193243
}
194244

src/client/base/backend/backend.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,12 @@ void Backend::init()
112112
connect(engine_, &Engine::setRobertFilterFinished, this, &Backend::onEngineSetRobertFilterFinished);
113113
connect(engine_, &Engine::syncRobertFinished, this, &Backend::onEngineSyncRobertFinished);
114114
connect(engine_, &Engine::splitTunnelingStartFailed, this, &Backend::splitTunnelingStartFailed);
115+
connect(engine_, &Engine::systemExtensionAvailabilityChanged, this, &Backend::systemExtensionAvailabilityChanged);
115116
connect(engine_, &Engine::autoEnableAntiCensorship, this, &Backend::onEngineAutoEnableAntiCensorship);
116117
connect(engine_, &Engine::connectionIdChanged, this, &Backend::connectionIdChanged);
117118
connect(engine_, &Engine::localDnsServerNotAvailable, this, &Backend::localDnsServerNotAvailable);
118119
connect(engine_, &Engine::bridgeApiAvailabilityChanged, this, &Backend::onEngineBridgeApiAvailabilityChanged);
119-
connect(engine_, &Engine::ipRotateFailed, this, &Backend::ipRotateFailed);
120+
connect(engine_, &Engine::ipRotateResult, this, &Backend::ipRotateResult);
120121
connect(engine_, &Engine::connectingHostnameChanged, this, &Backend::onEngineConnectingHostnameChanged);
121122
connect(engine_, &Engine::controldDevicesFetched, this, &Backend::controldDevicesFetched);
122123
threadEngine_->start(QThread::LowPriority);
@@ -135,6 +136,7 @@ void Backend::enableBFE_win()
135136

136137
void Backend::login(const QString &username, const QString &password, const QString &code2fa)
137138
{
139+
WS_ASSERT(loginState_ != LOGIN_STATE_LOGGING_IN);
138140
loginState_ = LOGIN_STATE_LOGGING_IN;
139141
bLastLoginWithAuthHash_ = false;
140142
lastUsername_ = username;
@@ -160,13 +162,15 @@ bool Backend::isSavedApiSettingsExists() const
160162

161163
void Backend::loginWithAuthHash()
162164
{
165+
WS_ASSERT(loginState_ != LOGIN_STATE_LOGGING_IN);
163166
loginState_ = LOGIN_STATE_LOGGING_IN;
164167
bLastLoginWithAuthHash_ = true;
165168
engine_->loginWithAuthHash();
166169
}
167170

168171
void Backend::loginWithLastLoginSettings()
169172
{
173+
WS_ASSERT(loginState_ != LOGIN_STATE_LOGGING_IN);
170174
loginState_ = LOGIN_STATE_LOGGING_IN;
171175
if (bLastLoginWithAuthHash_)
172176
loginWithAuthHash();
@@ -575,9 +579,9 @@ void Backend::onEngineSyncRobertFinished(bool success)
575579
emit syncRobertResult(success);
576580
}
577581

578-
void Backend::onEngineProtocolStatusChanged(const QVector<types::ProtocolStatus> &status)
582+
void Backend::onEngineProtocolStatusChanged(const QVector<types::ProtocolStatus> &status, bool isAutomaticMode)
579583
{
580-
emit protocolStatusChanged(status);
584+
emit protocolStatusChanged(status, isAutomaticMode);
581585
}
582586

583587
void Backend::onEngineEmergencyConnected()
@@ -889,10 +893,12 @@ void Backend::sendSplitTunneling(const types::SplitTunneling &st)
889893
QStringList ips;
890894
QStringList hosts;
891895
for (int i = 0; i < st.networkRoutes.size(); ++i) {
892-
if (st.networkRoutes[i].type == SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_IP) {
893-
ips << st.networkRoutes[i].name;
894-
} else if (st.networkRoutes[i].type == SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_HOSTNAME) {
895-
hosts << st.networkRoutes[i].name;
896+
if (st.networkRoutes[i].active) {
897+
if (st.networkRoutes[i].type == SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_IP) {
898+
ips << st.networkRoutes[i].name;
899+
} else if (st.networkRoutes[i].type == SPLIT_TUNNELING_NETWORK_ROUTE_TYPE_HOSTNAME) {
900+
hosts << st.networkRoutes[i].name;
901+
}
896902
}
897903
}
898904

@@ -1075,4 +1081,3 @@ void Backend::fetchControldDevices(const QString &apiKey)
10751081
{
10761082
engine_->fetchControldDevices(apiKey);
10771083
}
1078-

src/client/base/backend/backend.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ private slots:
148148
void onEngineRobertFiltersUpdated(bool success, const QVector<api_responses::RobertFilter> &filters);
149149
void onEngineSetRobertFilterFinished(bool success);
150150
void onEngineSyncRobertFinished(bool success);
151-
void onEngineProtocolStatusChanged(const QVector<types::ProtocolStatus> &status);
151+
void onEngineProtocolStatusChanged(const QVector<types::ProtocolStatus> &status, bool isAutomaticMode);
152152

153153
void onEngineEmergencyConnected();
154154
void onEngineEmergencyDisconnected();
@@ -215,6 +215,7 @@ private slots:
215215
void sessionStatusChanged(const api_responses::SessionStatus &sessionStatus);
216216
void checkUpdateChanged(const api_responses::CheckUpdate &checkUpdateInfo);
217217
void splitTunnelingStateChanged(bool isActive);
218+
void systemExtensionAvailabilityChanged(bool available);
218219

219220
void confirmEmailResult(bool bSuccess);
220221
void debugLogResult(bool bSuccess);
@@ -247,7 +248,7 @@ private slots:
247248

248249
void wireGuardAtKeyLimit();
249250
void wireGuardKeyLimitUserResponse(bool deleteOldestKey);
250-
void protocolStatusChanged(const QVector<types::ProtocolStatus> &status);
251+
void protocolStatusChanged(const QVector<types::ProtocolStatus> &status, bool isAutomaticMode);
251252

252253
void controldDevicesFetched(CONTROLD_FETCH_RESULT result, const QList<QPair<QString, QString>> &devices);
253254

@@ -256,7 +257,7 @@ private slots:
256257
void localDnsServerNotAvailable();
257258

258259
void bridgeApiAvailabilityChanged(bool isAvailable);
259-
void ipRotateFailed();
260+
void ipRotateResult(bool success);
260261

261262
private:
262263
bool isSavedApiSettingsExists_;

src/client/base/backend/preferences/preferences.cpp

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ Preferences::Preferences(QObject *parent) : QObject(parent)
2323

2424
Preferences::~Preferences()
2525
{
26-
// make sure timers are cleaned up; don't call clearLastKnownGoodProtocols() here,
27-
// because it will trigger a emit engineSettingsChanged();
28-
for (auto network : timers_.keys()) {
29-
timers_[network]->stop();
30-
SAFE_DELETE(timers_[network]);
31-
}
32-
timers_.clear();
3326
}
3427

3528
bool Preferences::isLaunchOnStartup() const
@@ -649,60 +642,6 @@ void Preferences::setCustomOvpnConfigsPath(const QString &path)
649642
}
650643
}
651644

652-
types::Protocol Preferences::networkLastKnownGoodProtocol(const QString &network) const
653-
{
654-
return engineSettings_.networkLastKnownGoodProtocol(network);
655-
}
656-
657-
uint Preferences::networkLastKnownGoodPort(const QString &network) const
658-
{
659-
return engineSettings_.networkLastKnownGoodPort(network);
660-
}
661-
662-
void Preferences::setNetworkLastKnownGoodProtocolPort(const QString &network, const types::Protocol &protocol, uint port)
663-
{
664-
if (engineSettings_.networkLastKnownGoodProtocol(network) != protocol ||
665-
engineSettings_.networkLastKnownGoodPort(network) != port)
666-
{
667-
// if a timer doesn't exist for this netowrk, create it, otherwise use the existing one
668-
if (!timers_.contains(network)) {
669-
QTimer *timer = new QTimer(this);
670-
timer->setSingleShot(true);
671-
connect(timer, &QTimer::timeout, this, [this, network] () {
672-
clearLastKnownGoodProtocols(network);
673-
});
674-
timers_[network] = timer;
675-
}
676-
// start or restart timer to clear this in 12 hours
677-
timers_[network]->start(12*60*60*1000);
678-
679-
engineSettings_.setNetworkLastKnownGoodProtocolPort(network, protocol, port);
680-
emitEngineSettingsChanged();
681-
emit networkLastKnownGoodProtocolPortChanged(network, protocol, port);
682-
}
683-
}
684-
685-
void Preferences::clearLastKnownGoodProtocols(const QString &network)
686-
{
687-
engineSettings_.clearLastKnownGoodProtocols(network);
688-
emitEngineSettingsChanged();
689-
690-
if (!network.isEmpty()) {
691-
if (timers_.contains(network)) {
692-
timers_[network]->stop();
693-
SAFE_DELETE(timers_[network]);
694-
timers_.remove(network);
695-
}
696-
emit networkLastKnownGoodProtocolPortChanged(network, types::Protocol(types::Protocol::TYPE::UNINITIALIZED), 0);
697-
} else {
698-
for (auto network : timers_.keys()) {
699-
timers_[network]->stop();
700-
SAFE_DELETE(timers_[network]);
701-
}
702-
timers_.clear();
703-
}
704-
}
705-
706645
QJsonObject Preferences::toJson() const
707646
{
708647
QJsonObject json;

src/client/base/backend/preferences/preferences.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,6 @@ class Preferences : public QObject
160160
bool isShowLocationLoad() const;
161161
void setShowLocationLoad(bool b);
162162

163-
types::Protocol networkLastKnownGoodProtocol(const QString &network) const;
164-
uint networkLastKnownGoodPort(const QString &network) const;
165-
void setNetworkLastKnownGoodProtocolPort(const QString &network, const types::Protocol &protocol, uint port);
166-
void clearLastKnownGoodProtocols(const QString &network = "");
167-
168163
QJsonObject toJson() const;
169164
void updateFromJson(const QJsonObject& ob);
170165

@@ -217,7 +212,6 @@ class Preferences : public QObject
217212
void networkPreferredProtocolsChanged(QMap<QString, types::ConnectionSettings> p);
218213
void splitTunnelingChanged(types::SplitTunneling st);
219214
void keepAliveChanged(bool b);
220-
void networkLastKnownGoodProtocolPortChanged(const QString &network, const types::Protocol &protocol, uint port);
221215

222216
// emit if any of the engine options have changed
223217
// don't emit in setEngineSettings()
@@ -230,7 +224,6 @@ class Preferences : public QObject
230224
types::GuiSettings guiSettings_;
231225

232226
bool isSettingEngineSettings_;
233-
QMap<QString, QTimer *> timers_;
234227

235228
void emitEngineSettingsChanged();
236229

src/client/base/backend/preferences/preferenceshelper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
PreferencesHelper::PreferencesHelper(QObject *parent) : QObject(parent),
66
isWifiSharingSupported_(true), isDockedToTray_(false), isExternalConfigMode_(false)
77
{
8-
availableLanguageCodes_ << "ar" << "cs" << "de" << "en" << "es" << "fa" << "fr" << "hi" << "id" << "it" << "ja" << "ko"
9-
<< "pl" << "pt" << "ru" << "tr" << "uk" << "vi" << "zh-CN" << "zh-TW";
8+
availableLanguageCodes_ << "ar" << "cs" << "de" << "el" << "en" << "es" << "fa" << "fr" << "hi" << "id" << "it" << "ja" << "ko"
9+
<< "pl" << "pt" << "ru" << "sk" << "tr" << "uk" << "vi" << "zh-CN" << "zh-TW";
1010
}
1111

1212
QString PreferencesHelper::buildVersion()

src/client/base/localipcserver/localipcserver.cpp

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ LocalIPCServer::LocalIPCServer(Backend *backend, QObject *parent) : QObject(pare
2323
connect(backend_, &Backend::updateVersionChanged, this, &LocalIPCServer::onBackendUpdateVersionChanged);
2424
connect(backend_, &Backend::connectionIdChanged, this, &LocalIPCServer::onBackendConnectionIdChanged);
2525
connect(backend_, &Backend::bridgeApiAvailabilityChanged, this, &LocalIPCServer::onBackendBridgeApiAvailabilityChanged);
26+
connect(backend_, &Backend::ipRotateResult, this, &LocalIPCServer::onBackendIpRotateResult);
2627

2728
connect(backend_->locationsModelManager(), &gui_locations::LocationsModelManager::deviceNameChanged, this, &LocalIPCServer::onLocationsModelManagerDeviceNameChanged);
2829
}
@@ -157,14 +158,32 @@ void LocalIPCServer::onConnectionCommandCallback(IPC::Command *command, IPC::Con
157158
IPC::CliCommands::SetKeyLimitBehavior *cmd = static_cast<IPC::CliCommands::SetKeyLimitBehavior *>(command);
158159
emit setKeyLimitBehavior(cmd->keyLimitDelete_);
159160
} else if (command->getStringId() == IPC::CliCommands::RotateIp::getCommandStringId()) {
160-
if (!isBridgeApiAvailable_) {
161+
if (awaitingIpRotateResult_) {
161162
IPC::CliCommands::Acknowledge cmd;
162-
cmd.code_ = 1;
163-
cmd.message_ = "Bridge API not available";
163+
cmd.code_ = 2;
164+
cmd.message_ = "IP rotate already in progress";
164165
sendCommand(cmd);
165166
return;
166167
}
167-
backend_->rotateIp();
168+
awaitingIpRotateResult_ = true;
169+
170+
qint64 msSinceLastResult = 0;
171+
if (lastIpRotateResultTime_.isValid()) {
172+
msSinceLastResult = lastIpRotateResultTime_.msecsTo(QDateTime::currentDateTime());
173+
}
174+
175+
int delayMs = qMax(0LL, 2000 - msSinceLastResult);
176+
QTimer::singleShot(delayMs, this, [this]() {
177+
if (!isBridgeApiAvailable_) {
178+
IPC::CliCommands::Acknowledge cmd;
179+
cmd.code_ = 1;
180+
cmd.message_ = "Bridge API not available";
181+
sendCommand(cmd);
182+
return;
183+
}
184+
backend_->rotateIp();
185+
});
186+
return;
168187
} else if (command->getStringId() == IPC::CliCommands::FavIp::getCommandStringId()) {
169188
if (!isBridgeApiAvailable_) {
170189
IPC::CliCommands::Acknowledge cmd;
@@ -285,6 +304,10 @@ void LocalIPCServer::onBackendConnectStateChanged(const types::ConnectState &sta
285304
invalidLocation_ = false;
286305
}
287306
}
307+
308+
if (awaitingIpRotateResult_ && connectState_.connectState != CONNECT_STATE_CONNECTED) {
309+
onBackendIpRotateResult(false);
310+
}
288311
}
289312

290313
void LocalIPCServer::onBackendProtocolPortChanged(const types::Protocol &protocol, uint port)
@@ -340,3 +363,23 @@ void LocalIPCServer::onLocationsModelManagerDeviceNameChanged(const QString &dev
340363
{
341364
deviceName_ = deviceName;
342365
}
366+
367+
void LocalIPCServer::onBackendIpRotateResult(bool success)
368+
{
369+
if (!awaitingIpRotateResult_) {
370+
return;
371+
}
372+
373+
awaitingIpRotateResult_ = false;
374+
lastIpRotateResultTime_ = QDateTime::currentDateTime();
375+
376+
IPC::CliCommands::Acknowledge cmd;
377+
if (success) {
378+
cmd.code_ = 0;
379+
cmd.message_ = "IP rotated.";
380+
} else {
381+
cmd.code_ = 1;
382+
cmd.message_ = "Could not rotate IP.";
383+
}
384+
sendCommand(cmd);
385+
}

0 commit comments

Comments
 (0)