Explicitly get circuit established status when Tor control is ready in case a circuit has already been established
This commit is contained in:
@@ -40,6 +40,9 @@ constexpr char kGetVersionCmd[] = "GETINFO version";
|
||||
constexpr char kGetVersionReply[] = "version=";
|
||||
constexpr char kGetSOCKSListenersCmd[] = "GETINFO net/listeners/socks";
|
||||
constexpr char kGetSOCKSListenersReply[] = "net/listeners/socks=";
|
||||
constexpr char kGetCircuitEstablishedCmd[] =
|
||||
"GETINFO status/circuit-established";
|
||||
constexpr char kGetCircuitEstablishedReply[] = "status/circuit-established=";
|
||||
|
||||
static std::string escapify(const char* buf, int len) {
|
||||
std::ostringstream s;
|
||||
@@ -461,6 +464,58 @@ void TorControl::GetSOCKSListenersDone(
|
||||
std::move(callback).Run(false, *listeners);
|
||||
}
|
||||
|
||||
void TorControl::GetCircuitEstablished(
|
||||
base::OnceCallback<void(bool error, bool established)> callback) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(owner_sequence_checker_);
|
||||
std::unique_ptr<std::string> established = std::make_unique<std::string>();
|
||||
std::string* established_p = established.get();
|
||||
io_task_runner_->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
&TorControl::DoCmd, weak_ptr_factory_.GetWeakPtr(),
|
||||
kGetCircuitEstablishedCmd,
|
||||
base::BindRepeating(&TorControl::GetCircuitEstablishedLine,
|
||||
weak_ptr_factory_.GetWeakPtr(), established_p),
|
||||
base::BindOnce(&TorControl::GetCircuitEstablishedDone,
|
||||
weak_ptr_factory_.GetWeakPtr(), std::move(established),
|
||||
std::move(callback))));
|
||||
}
|
||||
|
||||
void TorControl::GetCircuitEstablishedLine(std::string* established,
|
||||
const std::string& status,
|
||||
const std::string& reply) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
|
||||
if (status != "250" ||
|
||||
!base::StartsWith(reply, kGetCircuitEstablishedReply,
|
||||
base::CompareCase::SENSITIVE) ||
|
||||
!established->empty()) {
|
||||
VLOG(0) << "tor: unexpected " << kGetCircuitEstablishedCmd << " reply";
|
||||
return;
|
||||
}
|
||||
*established = reply.substr(strlen(kGetCircuitEstablishedReply));
|
||||
}
|
||||
|
||||
void TorControl::GetCircuitEstablishedDone(
|
||||
std::unique_ptr<std::string> established,
|
||||
base::OnceCallback<void(bool error, bool established)> callback,
|
||||
bool error,
|
||||
const std::string& status,
|
||||
const std::string& reply) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(io_sequence_checker_);
|
||||
bool result;
|
||||
if (*established == "1")
|
||||
result = true;
|
||||
else if (*established == "0")
|
||||
result = false;
|
||||
else
|
||||
error = true;
|
||||
if (error || status != "250" || reply != "OK" || established->empty()) {
|
||||
std::move(callback).Run(true, false);
|
||||
return;
|
||||
}
|
||||
std::move(callback).Run(false, result);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Writing state machine
|
||||
|
||||
|
||||
@@ -90,12 +90,15 @@ class TorControl {
|
||||
base::OnceCallback<void(bool error,
|
||||
const std::vector<std::string>& listeners)>
|
||||
callback);
|
||||
void GetCircuitEstablished(
|
||||
base::OnceCallback<void(bool error, bool established)> callback);
|
||||
|
||||
protected:
|
||||
friend class TorControlTest;
|
||||
FRIEND_TEST_ALL_PREFIXES(TorControlTest, ParseQuoted);
|
||||
FRIEND_TEST_ALL_PREFIXES(TorControlTest, ParseKV);
|
||||
FRIEND_TEST_ALL_PREFIXES(TorControlTest, ReadLine);
|
||||
FRIEND_TEST_ALL_PREFIXES(TorControlTest, GetCircuitEstablishedDone);
|
||||
|
||||
static bool ParseKV(const std::string& string,
|
||||
std::string* key,
|
||||
@@ -137,6 +140,15 @@ class TorControl {
|
||||
bool error,
|
||||
const std::string& status,
|
||||
const std::string& reply);
|
||||
void GetCircuitEstablishedLine(std::string* established,
|
||||
const std::string& status,
|
||||
const std::string& reply);
|
||||
void GetCircuitEstablishedDone(
|
||||
std::unique_ptr<std::string> established,
|
||||
base::OnceCallback<void(bool error, bool established)> callback,
|
||||
bool error,
|
||||
const std::string& status,
|
||||
const std::string& reply);
|
||||
|
||||
void DoSubscribe(TorControlEvent event,
|
||||
base::OnceCallback<void(bool error)> callback);
|
||||
|
||||
@@ -184,4 +184,120 @@ TEST(TorControlTest, ReadLine) {
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
TEST(TorControlTest, GetCircuitEstablishedDone) {
|
||||
content::BrowserTaskEnvironment task_environment;
|
||||
scoped_refptr<base::SequencedTaskRunner> io_task_runner =
|
||||
content::GetIOThreadTaskRunner({});
|
||||
|
||||
MockTorControlDelegate delegate;
|
||||
std::unique_ptr<TorControl> control =
|
||||
std::make_unique<TorControl>(&delegate, io_task_runner);
|
||||
|
||||
io_task_runner->PostTask(
|
||||
FROM_HERE, base::BindOnce(
|
||||
[](std::unique_ptr<TorControl> control) {
|
||||
std::unique_ptr<std::string> established =
|
||||
std::make_unique<std::string>("0");
|
||||
bool is_called = false;
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_FALSE(error);
|
||||
EXPECT_FALSE(result);
|
||||
},
|
||||
&is_called),
|
||||
false, "250", "OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
|
||||
is_called = false;
|
||||
established.reset(new std::string("1"));
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_FALSE(error);
|
||||
EXPECT_TRUE(result);
|
||||
},
|
||||
&is_called),
|
||||
false, "250", "OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
|
||||
// --- Error cases ---
|
||||
is_called = false;
|
||||
established.reset(new std::string("iambrave"));
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_TRUE(error);
|
||||
EXPECT_FALSE(result);
|
||||
},
|
||||
&is_called),
|
||||
false, "250", "OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
|
||||
is_called = false;
|
||||
established.reset(new std::string(""));
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_TRUE(error);
|
||||
EXPECT_FALSE(result);
|
||||
},
|
||||
&is_called),
|
||||
false, "250", "OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
|
||||
is_called = false;
|
||||
established.reset(new std::string("1"));
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_TRUE(error);
|
||||
EXPECT_FALSE(result);
|
||||
},
|
||||
&is_called),
|
||||
true, "250", "OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
|
||||
is_called = false;
|
||||
established.reset(new std::string("1"));
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_TRUE(error);
|
||||
EXPECT_FALSE(result);
|
||||
},
|
||||
&is_called),
|
||||
false, "500", "OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
|
||||
is_called = false;
|
||||
established.reset(new std::string("1"));
|
||||
control->GetCircuitEstablishedDone(
|
||||
std::move(established),
|
||||
base::BindOnce(
|
||||
[](bool* is_called, bool error, bool result) {
|
||||
*is_called = true;
|
||||
EXPECT_TRUE(error);
|
||||
EXPECT_FALSE(result);
|
||||
},
|
||||
&is_called),
|
||||
false, "500", "NOT_OK");
|
||||
EXPECT_TRUE(is_called);
|
||||
},
|
||||
std::move(control)));
|
||||
base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
} // namespace tor
|
||||
|
||||
@@ -233,6 +233,14 @@ void TorLauncherFactory::OnTorControlReady() {
|
||||
base::BindPostTask(base::SequencedTaskRunnerHandle::Get(),
|
||||
base::BindOnce(&TorLauncherFactory::GotSOCKSListeners,
|
||||
weak_ptr_factory_.GetWeakPtr())));
|
||||
// A Circuit might have been established when Tor control is ready, in that
|
||||
// case we will not receive circuit established events. So we query the status
|
||||
// directly as fail safe, otherwise Tor window might stuck in disconnected
|
||||
// state while Tor circuit is ready.
|
||||
control_->GetCircuitEstablished(base::BindPostTask(
|
||||
base::SequencedTaskRunnerHandle::Get(),
|
||||
base::BindOnce(&TorLauncherFactory::GotCircuitEstablished,
|
||||
weak_ptr_factory_.GetWeakPtr())));
|
||||
control_->Subscribe(tor::TorControlEvent::NETWORK_LIVENESS,
|
||||
base::DoNothing::Once<bool>());
|
||||
control_->Subscribe(tor::TorControlEvent::STATUS_CLIENT,
|
||||
@@ -277,6 +285,17 @@ void TorLauncherFactory::GotSOCKSListeners(
|
||||
observer.OnTorNewProxyURI(tor_proxy_uri);
|
||||
}
|
||||
|
||||
void TorLauncherFactory::GotCircuitEstablished(bool error, bool established) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
if (error) {
|
||||
VLOG(1) << "Failed to get circuit established!";
|
||||
return;
|
||||
}
|
||||
is_connected_ = established;
|
||||
for (auto& observer : observers_)
|
||||
observer.OnTorCircuitEstablished(established);
|
||||
}
|
||||
|
||||
void TorLauncherFactory::OnTorControlClosed(bool was_running) {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
VLOG(2) << "TOR CONTROL: Closed!";
|
||||
|
||||
@@ -78,6 +78,7 @@ class TorLauncherFactory : public tor::TorControl::Delegate {
|
||||
|
||||
void GotVersion(bool error, const std::string& version);
|
||||
void GotSOCKSListeners(bool error, const std::vector<std::string>& listeners);
|
||||
void GotCircuitEstablished(bool error, bool established);
|
||||
|
||||
void LaunchTorInternal();
|
||||
void RelaunchTor();
|
||||
|
||||
Reference in New Issue
Block a user