ftl_signal_strategy.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/signaling/ftl_signal_strategy.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/logging.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/memory/weak_ptr.h"
  10. #include "base/observer_list.h"
  11. #include "base/rand_util.h"
  12. #include "base/sequence_checker.h"
  13. #include "base/strings/string_number_conversions.h"
  14. #include "base/threading/sequenced_task_runner_handle.h"
  15. #include "remoting/base/logging.h"
  16. #include "remoting/base/oauth_token_getter.h"
  17. #include "remoting/base/protobuf_http_status.h"
  18. #include "remoting/signaling/ftl_device_id_provider.h"
  19. #include "remoting/signaling/ftl_messaging_client.h"
  20. #include "remoting/signaling/ftl_registration_manager.h"
  21. #include "remoting/signaling/signaling_address.h"
  22. #include "remoting/signaling/xmpp_constants.h"
  23. #include "services/network/public/cpp/shared_url_loader_factory.h"
  24. #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
  25. namespace remoting {
  26. class FtlSignalStrategy::Core {
  27. public:
  28. Core(std::unique_ptr<OAuthTokenGetter> oauth_token_getter,
  29. std::unique_ptr<RegistrationManager> registration_manager,
  30. std::unique_ptr<MessagingClient> messaging_client);
  31. Core(const Core&) = delete;
  32. Core& operator=(const Core&) = delete;
  33. ~Core();
  34. void Connect();
  35. void Disconnect();
  36. State GetState() const;
  37. Error GetError() const;
  38. const SignalingAddress& GetLocalAddress() const;
  39. void AddListener(Listener* listener);
  40. void RemoveListener(Listener* listener);
  41. bool SendStanza(std::unique_ptr<jingle_xmpp::XmlElement> stanza);
  42. bool SendMessage(const SignalingAddress& destination_address,
  43. const ftl::ChromotingMessage& message);
  44. bool IsSignInError() const;
  45. private:
  46. // Methods are called in the order below when Connect() is called.
  47. void OnGetOAuthTokenResponse(OAuthTokenGetter::Status status,
  48. const std::string& user_email,
  49. const std::string& access_token);
  50. void OnSignInGaiaResponse(const ProtobufHttpStatus& status);
  51. void StartReceivingMessages();
  52. void OnReceiveMessagesStreamStarted();
  53. void OnReceiveMessagesStreamClosed(const ProtobufHttpStatus& status);
  54. void OnMessageReceived(const ftl::Id& sender_id,
  55. const std::string& sender_registration_id,
  56. const ftl::ChromotingMessage& message);
  57. void SendMessageImpl(const SignalingAddress& receiver,
  58. const ftl::ChromotingMessage& message,
  59. MessagingClient::DoneCallback callback);
  60. void OnSendMessageResponse(const SignalingAddress& receiver,
  61. const std::string& stanza_id,
  62. const ProtobufHttpStatus& status);
  63. // Returns true if the status is handled.
  64. void HandleProtobufHttpStatusError(const base::Location& location,
  65. const ProtobufHttpStatus& status);
  66. void OnStanza(const SignalingAddress& sender_address,
  67. std::unique_ptr<jingle_xmpp::XmlElement> stanza);
  68. std::unique_ptr<OAuthTokenGetter> oauth_token_getter_;
  69. std::unique_ptr<RegistrationManager> registration_manager_;
  70. std::unique_ptr<MessagingClient> messaging_client_;
  71. std::string user_email_;
  72. SignalingAddress local_address_;
  73. base::CallbackListSubscription receive_message_subscription_;
  74. Error error_ = OK;
  75. bool is_sign_in_error_ = false;
  76. base::ObserverList<Listener, true> listeners_;
  77. SEQUENCE_CHECKER(sequence_checker_);
  78. base::WeakPtrFactory<Core> weak_factory_{this};
  79. };
  80. FtlSignalStrategy::Core::Core(
  81. std::unique_ptr<OAuthTokenGetter> oauth_token_getter,
  82. std::unique_ptr<RegistrationManager> registration_manager,
  83. std::unique_ptr<MessagingClient> messaging_client) {
  84. DCHECK(oauth_token_getter);
  85. DCHECK(registration_manager);
  86. DCHECK(messaging_client);
  87. oauth_token_getter_ = std::move(oauth_token_getter);
  88. registration_manager_ = std::move(registration_manager);
  89. messaging_client_ = std::move(messaging_client);
  90. }
  91. FtlSignalStrategy::Core::~Core() {
  92. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  93. Disconnect();
  94. }
  95. void FtlSignalStrategy::Core::Connect() {
  96. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  97. if (GetState() != DISCONNECTED) {
  98. LOG(WARNING) << "Signaling is not disconnected. State: " << GetState();
  99. return;
  100. }
  101. error_ = OK;
  102. is_sign_in_error_ = false;
  103. receive_message_subscription_ =
  104. messaging_client_->RegisterMessageCallback(base::BindRepeating(
  105. &Core::OnMessageReceived, weak_factory_.GetWeakPtr()));
  106. for (auto& observer : listeners_)
  107. observer.OnSignalStrategyStateChange(CONNECTING);
  108. StartReceivingMessages();
  109. }
  110. void FtlSignalStrategy::Core::Disconnect() {
  111. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  112. if (registration_manager_->IsSignedIn()) {
  113. registration_manager_->SignOut();
  114. }
  115. if (receive_message_subscription_) {
  116. local_address_ = SignalingAddress();
  117. receive_message_subscription_ = {};
  118. messaging_client_->StopReceivingMessages();
  119. for (auto& observer : listeners_)
  120. observer.OnSignalStrategyStateChange(DISCONNECTED);
  121. }
  122. }
  123. SignalStrategy::State FtlSignalStrategy::Core::GetState() const {
  124. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  125. if (!local_address_.empty()) {
  126. DCHECK(receive_message_subscription_);
  127. return CONNECTED;
  128. } else if (receive_message_subscription_) {
  129. return CONNECTING;
  130. } else {
  131. return DISCONNECTED;
  132. }
  133. }
  134. SignalStrategy::Error FtlSignalStrategy::Core::GetError() const {
  135. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  136. return error_;
  137. }
  138. const SignalingAddress& FtlSignalStrategy::Core::GetLocalAddress() const {
  139. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  140. return local_address_;
  141. }
  142. void FtlSignalStrategy::Core::AddListener(Listener* listener) {
  143. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  144. listeners_.AddObserver(listener);
  145. }
  146. void FtlSignalStrategy::Core::RemoveListener(Listener* listener) {
  147. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  148. listeners_.RemoveObserver(listener);
  149. }
  150. bool FtlSignalStrategy::Core::SendStanza(
  151. std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  152. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  153. if (GetState() != CONNECTED) {
  154. HOST_LOG << "Dropping signaling message because FTL is not connected.";
  155. return false;
  156. }
  157. std::string to_error;
  158. SignalingAddress to =
  159. SignalingAddress::Parse(stanza.get(), SignalingAddress::TO, &to_error);
  160. DCHECK(to_error.empty());
  161. // Synthesizing the from attribute in the message.
  162. stanza->SetAttr(kQNameFrom, local_address_.id());
  163. std::string stanza_id = stanza->Attr(kQNameId);
  164. ftl::ChromotingMessage crd_message;
  165. crd_message.mutable_xmpp()->set_stanza(stanza->Str());
  166. SendMessageImpl(to, crd_message,
  167. base::BindOnce(&Core::OnSendMessageResponse,
  168. weak_factory_.GetWeakPtr(), to, stanza_id));
  169. // Return false if the SendMessageImpl() call above resulted in the
  170. // SignalStrategy being disconnected.
  171. return GetState() == CONNECTED;
  172. }
  173. bool FtlSignalStrategy::Core::SendMessage(
  174. const SignalingAddress& destination_address,
  175. const ftl::ChromotingMessage& message) {
  176. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  177. if (GetState() != CONNECTED) {
  178. HOST_LOG << "Dropping message because FTL is not connected.";
  179. return false;
  180. }
  181. SendMessageImpl(
  182. destination_address, message,
  183. base::BindOnce(&Core::OnSendMessageResponse, weak_factory_.GetWeakPtr(),
  184. destination_address, std::string()));
  185. return true;
  186. }
  187. bool FtlSignalStrategy::Core::IsSignInError() const {
  188. return is_sign_in_error_;
  189. }
  190. void FtlSignalStrategy::Core::OnGetOAuthTokenResponse(
  191. OAuthTokenGetter::Status status,
  192. const std::string& user_email,
  193. const std::string& access_token) {
  194. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  195. if (status != OAuthTokenGetter::Status::SUCCESS) {
  196. switch (status) {
  197. case OAuthTokenGetter::Status::NETWORK_ERROR:
  198. error_ = SignalStrategy::Error::NETWORK_ERROR;
  199. break;
  200. case OAuthTokenGetter::Status::AUTH_ERROR:
  201. error_ = SignalStrategy::Error::AUTHENTICATION_FAILED;
  202. break;
  203. default:
  204. NOTREACHED();
  205. break;
  206. }
  207. is_sign_in_error_ = true;
  208. Disconnect();
  209. return;
  210. }
  211. user_email_ = user_email;
  212. StartReceivingMessages();
  213. }
  214. void FtlSignalStrategy::Core::OnSignInGaiaResponse(
  215. const ProtobufHttpStatus& status) {
  216. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  217. if (!status.ok()) {
  218. is_sign_in_error_ = true;
  219. HandleProtobufHttpStatusError(FROM_HERE, status);
  220. return;
  221. }
  222. StartReceivingMessages();
  223. }
  224. void FtlSignalStrategy::Core::StartReceivingMessages() {
  225. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  226. DCHECK_EQ(CONNECTING, GetState());
  227. DCHECK(!messaging_client_->IsReceivingMessages());
  228. if (user_email_.empty()) {
  229. oauth_token_getter_->CallWithToken(base::BindOnce(
  230. &Core::OnGetOAuthTokenResponse, weak_factory_.GetWeakPtr()));
  231. return;
  232. }
  233. if (!registration_manager_->IsSignedIn()) {
  234. registration_manager_->SignInGaia(base::BindOnce(
  235. &Core::OnSignInGaiaResponse, weak_factory_.GetWeakPtr()));
  236. return;
  237. }
  238. messaging_client_->StartReceivingMessages(
  239. base::BindOnce(&Core::OnReceiveMessagesStreamStarted,
  240. weak_factory_.GetWeakPtr()),
  241. base::BindOnce(&Core::OnReceiveMessagesStreamClosed,
  242. weak_factory_.GetWeakPtr()));
  243. }
  244. void FtlSignalStrategy::Core::OnReceiveMessagesStreamStarted() {
  245. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  246. local_address_ = SignalingAddress::CreateFtlSignalingAddress(
  247. user_email_, registration_manager_->GetRegistrationId());
  248. for (auto& observer : listeners_)
  249. observer.OnSignalStrategyStateChange(CONNECTED);
  250. }
  251. void FtlSignalStrategy::Core::OnReceiveMessagesStreamClosed(
  252. const ProtobufHttpStatus& status) {
  253. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  254. if (status.error_code() == ProtobufHttpStatus::Code::CANCELLED) {
  255. LOG(WARNING) << "ReceiveMessages stream closed with CANCELLED code.";
  256. }
  257. DCHECK(!status.ok());
  258. HandleProtobufHttpStatusError(FROM_HERE, status);
  259. }
  260. void FtlSignalStrategy::Core::OnMessageReceived(
  261. const ftl::Id& sender_id,
  262. const std::string& sender_registration_id,
  263. const ftl::ChromotingMessage& message) {
  264. for (auto& listener : listeners_) {
  265. if (listener.OnSignalStrategyIncomingMessage(
  266. sender_id, sender_registration_id, message)) {
  267. return;
  268. }
  269. }
  270. if (!message.has_xmpp()) {
  271. LOG(WARNING) << "Ignoring message that doesn't have XMPP field.";
  272. return;
  273. }
  274. auto sender_address = SignalingAddress::CreateFtlSignalingAddress(
  275. sender_id.id(), sender_registration_id);
  276. DCHECK(message.xmpp().has_stanza());
  277. auto stanza = base::WrapUnique<jingle_xmpp::XmlElement>(
  278. jingle_xmpp::XmlElement::ForStr(message.xmpp().stanza()));
  279. if (!stanza) {
  280. LOG(WARNING) << "Failed to parse XMPP: " << message.xmpp().stanza();
  281. return;
  282. }
  283. OnStanza(sender_address, std::move(stanza));
  284. }
  285. void FtlSignalStrategy::Core::SendMessageImpl(
  286. const SignalingAddress& receiver,
  287. const ftl::ChromotingMessage& message,
  288. MessagingClient::DoneCallback callback) {
  289. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  290. std::string receiver_username;
  291. std::string receiver_registration_id;
  292. bool get_info_result =
  293. receiver.GetFtlInfo(&receiver_username, &receiver_registration_id);
  294. if (!get_info_result) {
  295. LOG(DFATAL) << "Receiver is not in FTL address: " << receiver.id();
  296. return;
  297. }
  298. std::string message_payload;
  299. if (message.has_xmpp()) {
  300. message_payload = message.xmpp().stanza();
  301. } else if (message.has_echo()) {
  302. message_payload = message.echo().message();
  303. } else {
  304. message_payload = "Error displaying message due to unknown format.";
  305. }
  306. HOST_LOG << "Sending outgoing message:\n"
  307. << "Receiver: " << receiver_username << "\n"
  308. << "Receiver registration ID: " << receiver_registration_id << "\n"
  309. << message_payload
  310. << "\n=========================================================";
  311. messaging_client_->SendMessage(receiver_username, receiver_registration_id,
  312. message, std::move(callback));
  313. }
  314. void FtlSignalStrategy::Core::OnSendMessageResponse(
  315. const SignalingAddress& receiver,
  316. const std::string& stanza_id,
  317. const ProtobufHttpStatus& status) {
  318. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  319. if (status.ok()) {
  320. return;
  321. }
  322. if (status.error_code() == ProtobufHttpStatus::Code::UNAUTHENTICATED) {
  323. HandleProtobufHttpStatusError(FROM_HERE, status);
  324. return;
  325. }
  326. LOG(ERROR) << "Failed to send message to peer. Error code: "
  327. << static_cast<int>(status.error_code())
  328. << ", message: " << status.error_message();
  329. if (stanza_id.empty()) {
  330. // If the message sent was not related to signaling, then exit early.
  331. return;
  332. }
  333. // Fake an error message so JingleSession will take it as PEER_IS_OFFLINE.
  334. auto error_iq = std::make_unique<jingle_xmpp::XmlElement>(kQNameIq);
  335. error_iq->SetAttr(kQNameType, kIqTypeError);
  336. error_iq->SetAttr(kQNameId, stanza_id);
  337. error_iq->SetAttr(kQNameFrom, receiver.id());
  338. error_iq->SetAttr(kQNameTo, local_address_.id());
  339. OnStanza(receiver, std::move(error_iq));
  340. }
  341. void FtlSignalStrategy::Core::HandleProtobufHttpStatusError(
  342. const base::Location& location,
  343. const ProtobufHttpStatus& status) {
  344. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  345. DCHECK(!status.ok());
  346. // We don't map HTTP_UNAUTHORIZED to AUTHENTICATION_FAILED here, as it will
  347. // permanently terminate the host, which is not desirable since it might
  348. // happen when the FTL registration becomes invalid while the robot account
  349. // itself is still intact.
  350. // AUTHENTICATION_FAILED is only reported if the OAuthTokenGetter fails to
  351. // fetch the token.
  352. error_ = Error::NETWORK_ERROR;
  353. LOG(ERROR) << "Received server error. Error code: "
  354. << static_cast<int>(status.error_code())
  355. << ", message: " << status.error_message()
  356. << ", location: " << location.ToString();
  357. if (status.error_code() == ProtobufHttpStatus::Code::UNAUTHENTICATED ||
  358. status.error_code() == ProtobufHttpStatus::Code::PERMISSION_DENIED) {
  359. oauth_token_getter_->InvalidateCache();
  360. }
  361. Disconnect();
  362. }
  363. void FtlSignalStrategy::Core::OnStanza(
  364. const SignalingAddress& sender_address,
  365. std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  366. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  367. // Validate the schema and FTL IDs.
  368. if (stanza->Name() != kQNameIq) {
  369. LOG(DFATAL) << "Received unexpected non-IQ packet " << stanza->Str();
  370. return;
  371. }
  372. if (SignalingAddress(stanza->Attr(kQNameFrom)) != sender_address) {
  373. LOG(DFATAL) << "Expected sender: " << sender_address.id()
  374. << ", but received: " << stanza->Attr(kQNameFrom);
  375. return;
  376. }
  377. if (SignalingAddress(stanza->Attr(kQNameTo)) != local_address_) {
  378. LOG(DFATAL) << "Expected receiver: " << local_address_.id()
  379. << ", but received: " << stanza->Attr(kQNameTo);
  380. return;
  381. }
  382. HOST_LOG << "Received incoming stanza:\n"
  383. << stanza->Str()
  384. << "\n=========================================================";
  385. for (auto& listener : listeners_) {
  386. if (listener.OnSignalStrategyIncomingStanza(stanza.get()))
  387. return;
  388. }
  389. }
  390. FtlSignalStrategy::FtlSignalStrategy(
  391. std::unique_ptr<OAuthTokenGetter> oauth_token_getter,
  392. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  393. std::unique_ptr<FtlDeviceIdProvider> device_id_provider,
  394. SignalingTracker* signaling_tracker) {
  395. // TODO(yuweih): Just make FtlMessagingClient own FtlRegistrationManager and
  396. // call SignInGaia() transparently.
  397. auto registration_manager = std::make_unique<FtlRegistrationManager>(
  398. oauth_token_getter.get(), url_loader_factory,
  399. std::move(device_id_provider));
  400. auto messaging_client = std::make_unique<FtlMessagingClient>(
  401. oauth_token_getter.get(), url_loader_factory, registration_manager.get(),
  402. signaling_tracker);
  403. CreateCore(std::move(oauth_token_getter), std::move(registration_manager),
  404. std::move(messaging_client));
  405. }
  406. FtlSignalStrategy::FtlSignalStrategy(
  407. std::unique_ptr<OAuthTokenGetter> oauth_token_getter,
  408. std::unique_ptr<RegistrationManager> registration_manager,
  409. std::unique_ptr<MessagingClient> messaging_client) {
  410. CreateCore(std::move(oauth_token_getter), std::move(registration_manager),
  411. std::move(messaging_client));
  412. }
  413. FtlSignalStrategy::~FtlSignalStrategy() {
  414. // All listeners should be removed at this point, so it's safe to detach
  415. // |core_|.
  416. base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
  417. core_.release());
  418. }
  419. void FtlSignalStrategy::Connect() {
  420. core_->Connect();
  421. }
  422. void FtlSignalStrategy::Disconnect() {
  423. core_->Disconnect();
  424. }
  425. SignalStrategy::State FtlSignalStrategy::GetState() const {
  426. return core_->GetState();
  427. }
  428. SignalStrategy::Error FtlSignalStrategy::GetError() const {
  429. return core_->GetError();
  430. }
  431. const SignalingAddress& FtlSignalStrategy::GetLocalAddress() const {
  432. return core_->GetLocalAddress();
  433. }
  434. void FtlSignalStrategy::AddListener(Listener* listener) {
  435. core_->AddListener(listener);
  436. }
  437. void FtlSignalStrategy::RemoveListener(Listener* listener) {
  438. core_->RemoveListener(listener);
  439. }
  440. bool FtlSignalStrategy::SendStanza(
  441. std::unique_ptr<jingle_xmpp::XmlElement> stanza) {
  442. return core_->SendStanza(std::move(stanza));
  443. }
  444. bool FtlSignalStrategy::SendMessage(const SignalingAddress& destination_address,
  445. const ftl::ChromotingMessage& message) {
  446. return core_->SendMessage(destination_address, message);
  447. }
  448. std::string FtlSignalStrategy::GetNextId() {
  449. return base::NumberToString(base::RandUint64());
  450. }
  451. bool FtlSignalStrategy::IsSignInError() const {
  452. return core_->IsSignInError();
  453. }
  454. void FtlSignalStrategy::CreateCore(
  455. std::unique_ptr<OAuthTokenGetter> oauth_token_getter,
  456. std::unique_ptr<RegistrationManager> registration_manager,
  457. std::unique_ptr<MessagingClient> messaging_client) {
  458. core_ = std::make_unique<Core>(std::move(oauth_token_getter),
  459. std::move(registration_manager),
  460. std::move(messaging_client));
  461. }
  462. } // namespace remoting