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
5 #include "cast/common/channel/virtual_connection_manager.h"
6
7 #include <type_traits>
8
9 namespace openscreen {
10 namespace cast {
11
12 VirtualConnectionManager::VirtualConnectionManager() = default;
13
14 VirtualConnectionManager::~VirtualConnectionManager() = default;
15
AddConnection(VirtualConnection virtual_connection,VirtualConnection::AssociatedData associated_data)16 void VirtualConnectionManager::AddConnection(
17 VirtualConnection virtual_connection,
18 VirtualConnection::AssociatedData associated_data) {
19 auto& socket_map = connections_[virtual_connection.socket_id];
20 auto local_entries = socket_map.equal_range(virtual_connection.local_id);
21 auto it = std::find_if(
22 local_entries.first, local_entries.second,
23 [&virtual_connection](const std::pair<std::string, VCTail>& entry) {
24 return entry.second.peer_id == virtual_connection.peer_id;
25 });
26 if (it == socket_map.end()) {
27 socket_map.emplace(std::move(virtual_connection.local_id),
28 VCTail{std::move(virtual_connection.peer_id),
29 std::move(associated_data)});
30 }
31 }
32
RemoveConnection(const VirtualConnection & virtual_connection,VirtualConnection::CloseReason reason)33 bool VirtualConnectionManager::RemoveConnection(
34 const VirtualConnection& virtual_connection,
35 VirtualConnection::CloseReason reason) {
36 auto socket_entry = connections_.find(virtual_connection.socket_id);
37 if (socket_entry == connections_.end()) {
38 return false;
39 }
40
41 auto& socket_map = socket_entry->second;
42 auto local_entries = socket_map.equal_range(virtual_connection.local_id);
43 if (local_entries.first == socket_map.end()) {
44 return false;
45 }
46 for (auto it = local_entries.first; it != local_entries.second; ++it) {
47 if (it->second.peer_id == virtual_connection.peer_id) {
48 socket_map.erase(it);
49 if (socket_map.empty()) {
50 connections_.erase(socket_entry);
51 }
52 return true;
53 }
54 }
55 return false;
56 }
57
RemoveConnectionsByLocalId(const std::string & local_id,VirtualConnection::CloseReason reason)58 size_t VirtualConnectionManager::RemoveConnectionsByLocalId(
59 const std::string& local_id,
60 VirtualConnection::CloseReason reason) {
61 size_t removed_count = 0;
62 for (auto socket_entry = connections_.begin();
63 socket_entry != connections_.end();) {
64 auto& socket_map = socket_entry->second;
65 auto local_entries = socket_map.equal_range(local_id);
66 if (local_entries.first != socket_map.end()) {
67 size_t current_count =
68 std::distance(local_entries.first, local_entries.second);
69 removed_count += current_count;
70 socket_map.erase(local_entries.first, local_entries.second);
71 if (socket_map.empty()) {
72 socket_entry = connections_.erase(socket_entry);
73 } else {
74 ++socket_entry;
75 }
76 } else {
77 ++socket_entry;
78 }
79 }
80 return removed_count;
81 }
82
RemoveConnectionsBySocketId(int socket_id,VirtualConnection::CloseReason reason)83 size_t VirtualConnectionManager::RemoveConnectionsBySocketId(
84 int socket_id,
85 VirtualConnection::CloseReason reason) {
86 auto entry = connections_.find(socket_id);
87 if (entry == connections_.end()) {
88 return 0;
89 }
90
91 size_t removed_count = entry->second.size();
92 connections_.erase(entry);
93
94 return removed_count;
95 }
96
97 absl::optional<const VirtualConnection::AssociatedData*>
GetConnectionData(const VirtualConnection & virtual_connection) const98 VirtualConnectionManager::GetConnectionData(
99 const VirtualConnection& virtual_connection) const {
100 auto socket_entry = connections_.find(virtual_connection.socket_id);
101 if (socket_entry == connections_.end()) {
102 return absl::nullopt;
103 }
104
105 auto& socket_map = socket_entry->second;
106 auto local_entries = socket_map.equal_range(virtual_connection.local_id);
107 if (local_entries.first == socket_map.end()) {
108 return absl::nullopt;
109 }
110 for (auto it = local_entries.first; it != local_entries.second; ++it) {
111 if (it->second.peer_id == virtual_connection.peer_id) {
112 return &it->second.data;
113 }
114 }
115 return absl::nullopt;
116 }
117
118 } // namespace cast
119 } // namespace openscreen
120