websocket_endpoint_lock_manager.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright 2014 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 "net/socket/websocket_endpoint_lock_manager.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/location.h"
  9. #include "base/logging.h"
  10. #include "base/task/single_thread_task_runner.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "net/base/net_errors.h"
  13. namespace net {
  14. namespace {
  15. // This delay prevents DoS attacks.
  16. // TODO(ricea): Replace this with randomised truncated exponential backoff.
  17. // See crbug.com/377613.
  18. const int kUnlockDelayInMs = 10;
  19. } // namespace
  20. WebSocketEndpointLockManager::Waiter::~Waiter() {
  21. if (next()) {
  22. DCHECK(previous());
  23. RemoveFromList();
  24. }
  25. }
  26. WebSocketEndpointLockManager::LockReleaser::LockReleaser(
  27. WebSocketEndpointLockManager* websocket_endpoint_lock_manager,
  28. IPEndPoint endpoint)
  29. : websocket_endpoint_lock_manager_(websocket_endpoint_lock_manager),
  30. endpoint_(endpoint) {
  31. websocket_endpoint_lock_manager->RegisterLockReleaser(this, endpoint);
  32. }
  33. WebSocketEndpointLockManager::LockReleaser::~LockReleaser() {
  34. if (websocket_endpoint_lock_manager_) {
  35. websocket_endpoint_lock_manager_->UnlockEndpoint(endpoint_);
  36. }
  37. }
  38. WebSocketEndpointLockManager::WebSocketEndpointLockManager()
  39. : unlock_delay_(base::Milliseconds(kUnlockDelayInMs)) {}
  40. WebSocketEndpointLockManager::~WebSocketEndpointLockManager() {
  41. DCHECK_EQ(lock_info_map_.size(), pending_unlock_count_);
  42. }
  43. int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint,
  44. Waiter* waiter) {
  45. LockInfoMap::value_type insert_value(endpoint, LockInfo());
  46. std::pair<LockInfoMap::iterator, bool> rv =
  47. lock_info_map_.insert(insert_value);
  48. LockInfo& lock_info_in_map = rv.first->second;
  49. if (rv.second) {
  50. DVLOG(3) << "Locking endpoint " << endpoint.ToString();
  51. lock_info_in_map.queue = std::make_unique<LockInfo::WaiterQueue>();
  52. return OK;
  53. }
  54. DVLOG(3) << "Waiting for endpoint " << endpoint.ToString();
  55. lock_info_in_map.queue->Append(waiter);
  56. return ERR_IO_PENDING;
  57. }
  58. void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) {
  59. auto lock_info_it = lock_info_map_.find(endpoint);
  60. if (lock_info_it == lock_info_map_.end())
  61. return;
  62. LockReleaser* lock_releaser = lock_info_it->second.lock_releaser;
  63. if (lock_releaser) {
  64. lock_info_it->second.lock_releaser = nullptr;
  65. lock_releaser->websocket_endpoint_lock_manager_ = nullptr;
  66. }
  67. UnlockEndpointAfterDelay(endpoint);
  68. }
  69. bool WebSocketEndpointLockManager::IsEmpty() const {
  70. return lock_info_map_.empty();
  71. }
  72. base::TimeDelta WebSocketEndpointLockManager::SetUnlockDelayForTesting(
  73. base::TimeDelta new_delay) {
  74. base::TimeDelta old_delay = unlock_delay_;
  75. unlock_delay_ = new_delay;
  76. return old_delay;
  77. }
  78. WebSocketEndpointLockManager::LockInfo::LockInfo() : lock_releaser(nullptr) {}
  79. WebSocketEndpointLockManager::LockInfo::~LockInfo() {
  80. DCHECK(!lock_releaser);
  81. }
  82. WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs)
  83. : lock_releaser(rhs.lock_releaser) {
  84. DCHECK(!rhs.queue);
  85. }
  86. void WebSocketEndpointLockManager::RegisterLockReleaser(
  87. LockReleaser* lock_releaser,
  88. IPEndPoint endpoint) {
  89. DCHECK(lock_releaser);
  90. auto lock_info_it = lock_info_map_.find(endpoint);
  91. CHECK(lock_info_it != lock_info_map_.end());
  92. DCHECK(!lock_info_it->second.lock_releaser);
  93. lock_info_it->second.lock_releaser = lock_releaser;
  94. DVLOG(3) << "Registered (LockReleaser*)" << lock_releaser << " for "
  95. << endpoint.ToString();
  96. }
  97. void WebSocketEndpointLockManager::UnlockEndpointAfterDelay(
  98. const IPEndPoint& endpoint) {
  99. DVLOG(3) << "Delaying " << unlock_delay_.InMilliseconds()
  100. << "ms before unlocking endpoint " << endpoint.ToString();
  101. ++pending_unlock_count_;
  102. base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
  103. FROM_HERE,
  104. base::BindOnce(&WebSocketEndpointLockManager::DelayedUnlockEndpoint,
  105. weak_factory_.GetWeakPtr(), endpoint),
  106. unlock_delay_);
  107. }
  108. void WebSocketEndpointLockManager::DelayedUnlockEndpoint(
  109. const IPEndPoint& endpoint) {
  110. auto lock_info_it = lock_info_map_.find(endpoint);
  111. DCHECK_GT(pending_unlock_count_, 0U);
  112. --pending_unlock_count_;
  113. if (lock_info_it == lock_info_map_.end())
  114. return;
  115. DCHECK(!lock_info_it->second.lock_releaser);
  116. LockInfo::WaiterQueue* queue = lock_info_it->second.queue.get();
  117. DCHECK(queue);
  118. if (queue->empty()) {
  119. DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString();
  120. lock_info_map_.erase(lock_info_it);
  121. return;
  122. }
  123. DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString()
  124. << " and activating next waiter";
  125. Waiter* next_job = queue->head()->value();
  126. next_job->RemoveFromList();
  127. next_job->GotEndpointLock();
  128. }
  129. } // namespace net