Home | History | Annotate | Download | only in socket
      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 
      5 #include "net/socket/websocket_endpoint_lock_manager.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/logging.h"
     10 #include "net/base/net_errors.h"
     11 #include "net/base/net_log.h"
     12 
     13 namespace net {
     14 
     15 WebSocketEndpointLockManager::Waiter::~Waiter() {
     16   if (next()) {
     17     DCHECK(previous());
     18     RemoveFromList();
     19   }
     20 }
     21 
     22 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() {
     23   return Singleton<WebSocketEndpointLockManager>::get();
     24 }
     25 
     26 int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint,
     27                                                Waiter* waiter) {
     28   LockInfoMap::value_type insert_value(endpoint, LockInfo());
     29   std::pair<LockInfoMap::iterator, bool> rv =
     30       lock_info_map_.insert(insert_value);
     31   LockInfo& lock_info_in_map = rv.first->second;
     32   if (rv.second) {
     33     DVLOG(3) << "Locking endpoint " << endpoint.ToString();
     34     lock_info_in_map.queue.reset(new LockInfo::WaiterQueue);
     35     return OK;
     36   }
     37   DVLOG(3) << "Waiting for endpoint " << endpoint.ToString();
     38   lock_info_in_map.queue->Append(waiter);
     39   return ERR_IO_PENDING;
     40 }
     41 
     42 void WebSocketEndpointLockManager::RememberSocket(StreamSocket* socket,
     43                                                   const IPEndPoint& endpoint) {
     44   LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint);
     45   CHECK(lock_info_it != lock_info_map_.end());
     46   bool inserted =
     47       socket_lock_info_map_.insert(SocketLockInfoMap::value_type(
     48                                        socket, lock_info_it)).second;
     49   DCHECK(inserted);
     50   DCHECK(!lock_info_it->second.socket);
     51   lock_info_it->second.socket = socket;
     52   DVLOG(3) << "Remembered (StreamSocket*)" << socket << " for "
     53            << endpoint.ToString() << " (" << socket_lock_info_map_.size()
     54            << " socket(s) remembered)";
     55 }
     56 
     57 void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) {
     58   SocketLockInfoMap::iterator socket_it = socket_lock_info_map_.find(socket);
     59   if (socket_it == socket_lock_info_map_.end())
     60     return;
     61 
     62   LockInfoMap::iterator lock_info_it = socket_it->second;
     63 
     64   DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for "
     65            << lock_info_it->first.ToString() << " ("
     66            << socket_lock_info_map_.size() << " socket(s) left)";
     67   socket_lock_info_map_.erase(socket_it);
     68   DCHECK(socket == lock_info_it->second.socket);
     69   lock_info_it->second.socket = NULL;
     70   UnlockEndpointByIterator(lock_info_it);
     71 }
     72 
     73 void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) {
     74   LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint);
     75   if (lock_info_it == lock_info_map_.end())
     76     return;
     77 
     78   UnlockEndpointByIterator(lock_info_it);
     79 }
     80 
     81 bool WebSocketEndpointLockManager::IsEmpty() const {
     82   return lock_info_map_.empty() && socket_lock_info_map_.empty();
     83 }
     84 
     85 WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {}
     86 WebSocketEndpointLockManager::LockInfo::~LockInfo() {
     87   DCHECK(!socket);
     88 }
     89 
     90 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs)
     91     : socket(rhs.socket) {
     92   DCHECK(!rhs.queue);
     93 }
     94 
     95 WebSocketEndpointLockManager::WebSocketEndpointLockManager() {}
     96 
     97 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() {
     98   DCHECK(lock_info_map_.empty());
     99   DCHECK(socket_lock_info_map_.empty());
    100 }
    101 
    102 void WebSocketEndpointLockManager::UnlockEndpointByIterator(
    103     LockInfoMap::iterator lock_info_it) {
    104   if (lock_info_it->second.socket)
    105     EraseSocket(lock_info_it);
    106   LockInfo::WaiterQueue* queue = lock_info_it->second.queue.get();
    107   DCHECK(queue);
    108   if (queue->empty()) {
    109     DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString();
    110     lock_info_map_.erase(lock_info_it);
    111     return;
    112   }
    113 
    114   DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString()
    115            << " and activating next waiter";
    116   Waiter* next_job = queue->head()->value();
    117   next_job->RemoveFromList();
    118   // This must be last to minimise the excitement caused by re-entrancy.
    119   next_job->GotEndpointLock();
    120 }
    121 
    122 void WebSocketEndpointLockManager::EraseSocket(
    123     LockInfoMap::iterator lock_info_it) {
    124   DVLOG(3) << "Removing (StreamSocket*)" << lock_info_it->second.socket
    125            << " for " << lock_info_it->first.ToString() << " ("
    126            << socket_lock_info_map_.size() << " socket(s) left)";
    127   size_t erased = socket_lock_info_map_.erase(lock_info_it->second.socket);
    128   DCHECK_EQ(1U, erased);
    129   lock_info_it->second.socket = NULL;
    130 }
    131 
    132 }  // namespace net
    133