summaryrefslogtreecommitdiffstats
path: root/net/socket/websocket_endpoint_lock_manager.cc
blob: c8d9a3b0a4602ab2cf93c249df3f2be34c7e5229 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/socket/websocket_endpoint_lock_manager.h"

#include <utility>

#include "base/logging.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"

namespace net {

WebSocketEndpointLockManager::Waiter::~Waiter() {
  if (next()) {
    DCHECK(previous());
    RemoveFromList();
  }
}

WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() {
  return Singleton<WebSocketEndpointLockManager>::get();
}

int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint,
                                               Waiter* waiter) {
  EndPointWaiterMap::value_type insert_value(endpoint, NULL);
  std::pair<EndPointWaiterMap::iterator, bool> rv =
      endpoint_waiter_map_.insert(insert_value);
  if (rv.second) {
    DVLOG(3) << "Locking endpoint " << endpoint.ToString();
    rv.first->second = new ConnectJobQueue;
    return OK;
  }
  DVLOG(3) << "Waiting for endpoint " << endpoint.ToString();
  rv.first->second->Append(waiter);
  return ERR_IO_PENDING;
}

void WebSocketEndpointLockManager::RememberSocket(StreamSocket* socket,
                                                  const IPEndPoint& endpoint) {
  bool inserted = socket_endpoint_map_.insert(SocketEndPointMap::value_type(
                                                  socket, endpoint)).second;
  DCHECK(inserted);
  DCHECK(endpoint_waiter_map_.find(endpoint) != endpoint_waiter_map_.end());
  DVLOG(3) << "Remembered (StreamSocket*)" << socket << " for "
           << endpoint.ToString() << " (" << socket_endpoint_map_.size()
           << " sockets remembered)";
}

void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) {
  SocketEndPointMap::iterator socket_it = socket_endpoint_map_.find(socket);
  if (socket_it == socket_endpoint_map_.end()) {
    DVLOG(3) << "Ignoring request to unlock already-unlocked socket"
                "(StreamSocket*)" << socket;
    return;
  }
  const IPEndPoint& endpoint = socket_it->second;
  DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for "
           << endpoint.ToString() << " (" << socket_endpoint_map_.size()
           << " sockets left)";
  UnlockEndpoint(endpoint);
  socket_endpoint_map_.erase(socket_it);
}

void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) {
  EndPointWaiterMap::iterator found_it = endpoint_waiter_map_.find(endpoint);
  CHECK(found_it != endpoint_waiter_map_.end());  // Security critical
  ConnectJobQueue* queue = found_it->second;
  if (queue->empty()) {
    DVLOG(3) << "Unlocking endpoint " << endpoint.ToString();
    delete queue;
    endpoint_waiter_map_.erase(found_it);
  } else {
    DVLOG(3) << "Unlocking endpoint " << endpoint.ToString()
             << " and activating next waiter";
    Waiter* next_job = queue->head()->value();
    next_job->RemoveFromList();
    next_job->GotEndpointLock();
  }
}

bool WebSocketEndpointLockManager::IsEmpty() const {
  return endpoint_waiter_map_.empty() && socket_endpoint_map_.empty();
}

WebSocketEndpointLockManager::WebSocketEndpointLockManager() {}

WebSocketEndpointLockManager::~WebSocketEndpointLockManager() {
  DCHECK(endpoint_waiter_map_.empty());
  DCHECK(socket_endpoint_map_.empty());
}

}  // namespace net