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