blob: c8d9a3b0a4602ab2cf93c249df3f2be34c7e5229 [file] [log] [blame]
// 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