diff --git a/server/Makefile.am b/server/Makefile.am
index edecf6c5..ab5ba8e1 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -97,6 +97,7 @@ libserver_la_SOURCES = \
cursor-channel-client.h \
cursor-channel.h \
utils.hpp \
+ safe-list.hpp \
dcc.cpp \
dcc.h \
dcc-private.h \
diff --git a/server/meson.build b/server/meson.build
index 458d6f31..aaa173ae 100644
--- a/server/meson.build
+++ b/server/meson.build
@@ -57,6 +57,7 @@ spice_server_sources = [
'cursor-channel-client.h',
'cursor-channel.h',
'utils.hpp',
+ 'safe-list.hpp',
'dcc.cpp',
'dcc.h',
'dcc-private.h',
diff --git a/server/safe-list.hpp b/server/safe-list.hpp
new file mode 100644
index 00000000..1edbe532
--- /dev/null
+++ b/server/safe-list.hpp
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2020 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see .
+*/
+
+/* Implementation of a list with more "safe" iterators.
+ * Specifically the item under an iterator can be removed while scanning
+ * the list. This to allow objects in the list to delete themselves from
+ * the list.
+ */
+#pragma once
+
+#include
+#include
+#include
+
+#include "push-visibility.h"
+
+namespace red {
+
+template
+class safe_list
+{
+ typedef typename std::forward_list wrapped;
+ typename std::forward_list list;
+ class iterator;
+public:
+ void push_front(const T& v)
+ {
+ list.push_front(v);
+ }
+ void remove(const T& v)
+ {
+ list.remove(v);
+ }
+ void clear()
+ {
+ list.clear();
+ }
+ void pop_front()
+ {
+ list.pop_front();
+ }
+ iterator begin() noexcept
+ {
+ return iterator(list.begin());
+ }
+ iterator end() noexcept
+ {
+ return iterator(list.end());
+ }
+ size_t size()
+ {
+ return std::distance(begin(), end());
+ }
+ bool empty() const
+ {
+ return list.empty();
+ }
+};
+
+template
+class safe_list::iterator: public std::iterator
+{
+ typedef typename std::forward_list::iterator wrapped;
+ wrapped curr, next;
+public:
+ iterator(wrapped curr) :
+ curr(curr),
+ next(curr != wrapped() ? ++curr : wrapped())
+ {
+ }
+ iterator& operator++()
+ {
+ curr = next;
+ if (next != wrapped()) {
+ ++next;
+ }
+ return *this;
+ }
+ iterator operator++(int)
+ {
+ iterator tmp(*this);
+ operator++();
+ return tmp;
+ }
+ bool operator==(const iterator& rhs) const
+ {
+ return curr == rhs.curr;
+ }
+ bool operator!=(const iterator& rhs) const
+ {
+ return curr != rhs.curr;
+ }
+ T& operator*()
+ {
+ return *curr;
+ }
+};
+
+} // namespace red
+
+#include "pop-visibility.h"