face: UdpTransport
Change-Id: I54f43248785437cdf951d50099e46e9689962a75
Refs: #3168
diff --git a/daemon/face/datagram-face.hpp b/daemon/face/datagram-face.hpp
deleted file mode 100644
index a55fb8c..0000000
--- a/daemon/face/datagram-face.hpp
+++ /dev/null
@@ -1,300 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
-#define NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
-
-#include "face.hpp"
-#include "core/global-io.hpp"
-
-namespace nfd {
-
-struct Unicast {};
-struct Multicast {};
-
-template<class Protocol, class Addressing = Unicast>
-class DatagramFace : public Face
-{
-public:
- typedef Protocol protocol;
-
- /** \brief Construct datagram face
- *
- * \param socket Protocol-specific socket for the created face
- */
- DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
- typename protocol::socket socket);
-
- // from Face
- void
- sendInterest(const Interest& interest) DECL_OVERRIDE;
-
- void
- sendData(const Data& data) DECL_OVERRIDE;
-
- void
- close() DECL_OVERRIDE;
-
- void
- receiveDatagram(const uint8_t* buffer,
- size_t nBytesReceived,
- const boost::system::error_code& error);
-
-protected:
- void
- processErrorCode(const boost::system::error_code& error);
-
- void
- handleSend(const boost::system::error_code& error,
- size_t nBytesSent,
- const Block& payload);
-
- void
- handleReceive(const boost::system::error_code& error,
- size_t nBytesReceived);
-
- void
- keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face);
-
- void
- closeSocket();
-
- bool
- hasBeenUsedRecently() const;
-
- /**
- * \brief Set m_hasBeenUsedRecently to false
- */
- void
- resetRecentUsage();
-
-protected:
- typename protocol::socket m_socket;
-
- NFD_LOG_INCLASS_DECLARE();
-
-private:
- uint8_t m_inputBuffer[ndn::MAX_NDN_PACKET_SIZE];
- bool m_hasBeenUsedRecently;
-};
-
-
-template<class T, class U>
-inline
-DatagramFace<T, U>::DatagramFace(const FaceUri& remoteUri, const FaceUri& localUri,
- typename DatagramFace::protocol::socket socket)
- : Face(remoteUri, localUri, false, std::is_same<U, Multicast>::value)
- , m_socket(std::move(socket))
-{
- NFD_LOG_FACE_INFO("Creating face");
-
- m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
- bind(&DatagramFace<T, U>::handleReceive, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred));
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::sendInterest(const Interest& interest)
-{
- NFD_LOG_FACE_TRACE(__func__);
-
- this->emitSignal(onSendInterest, interest);
-
- const Block& payload = interest.wireEncode();
- m_socket.async_send(boost::asio::buffer(payload.wire(), payload.size()),
- bind(&DatagramFace<T, U>::handleSend, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred,
- payload));
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::sendData(const Data& data)
-{
- NFD_LOG_FACE_TRACE(__func__);
-
- this->emitSignal(onSendData, data);
-
- const Block& payload = data.wireEncode();
- m_socket.async_send(boost::asio::buffer(payload.wire(), payload.size()),
- bind(&DatagramFace<T, U>::handleSend, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred,
- payload));
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::close()
-{
- if (!m_socket.is_open())
- return;
-
- NFD_LOG_FACE_INFO("Closing face");
-
- closeSocket();
- this->fail("Face closed");
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::processErrorCode(const boost::system::error_code& error)
-{
- if (error == boost::asio::error::operation_aborted) // when cancel() is called
- return;
-
- if (getPersistency() == ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERMANENT) {
- NFD_LOG_FACE_DEBUG("Permanent face ignores error: " << error.message());
- return;
- }
-
- if (!m_socket.is_open()) {
- this->fail("Tunnel closed");
- return;
- }
-
- if (error != boost::asio::error::eof)
- NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
-
- closeSocket();
-
- if (error == boost::asio::error::eof)
- this->fail("Tunnel closed");
- else
- this->fail(error.message());
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::handleSend(const boost::system::error_code& error,
- size_t nBytesSent,
- const Block& payload)
-// 'payload' is unused; it's needed to retain the underlying Buffer
-{
- if (error)
- return processErrorCode(error);
-
- NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
- this->getMutableCounters().getNOutBytes() += nBytesSent;
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::handleReceive(const boost::system::error_code& error,
- size_t nBytesReceived)
-{
- receiveDatagram(m_inputBuffer, nBytesReceived, error);
-
- if (m_socket.is_open())
- m_socket.async_receive(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
- bind(&DatagramFace<T, U>::handleReceive, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred));
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::receiveDatagram(const uint8_t* buffer,
- size_t nBytesReceived,
- const boost::system::error_code& error)
-{
- if (error)
- return processErrorCode(error);
-
- NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
- this->getMutableCounters().getNInBytes() += nBytesReceived;
-
- bool isOk = false;
- Block element;
- std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
- if (!isOk)
- {
- NFD_LOG_FACE_WARN("Failed to parse incoming packet");
- // This message won't extend the face lifetime
- return;
- }
-
- if (element.size() != nBytesReceived)
- {
- NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
- // This message won't extend the face lifetime
- return;
- }
-
- if (!this->decodeAndDispatchInput(element))
- {
- NFD_LOG_FACE_WARN("Received unrecognized TLV block of type " << element.type());
- // This message won't extend the face lifetime
- return;
- }
-
- m_hasBeenUsedRecently = true;
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted(const shared_ptr<Face>& face)
-{
- NFD_LOG_FACE_TRACE(__func__);
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::closeSocket()
-{
- NFD_LOG_FACE_TRACE(__func__);
-
- // use the non-throwing variants and ignore errors, if any
- boost::system::error_code error;
- m_socket.shutdown(protocol::socket::shutdown_both, error);
- m_socket.close(error);
- // after this, handlers will be called with an error code
-
- // ensure that the Face object is alive at least until all pending
- // handlers are dispatched
- getGlobalIoService().post(bind(&DatagramFace<T, U>::keepFaceAliveUntilAllHandlersExecuted,
- this, this->shared_from_this()));
-}
-
-template<class T, class U>
-inline bool
-DatagramFace<T, U>::hasBeenUsedRecently() const
-{
- return m_hasBeenUsedRecently;
-}
-
-template<class T, class U>
-inline void
-DatagramFace<T, U>::resetRecentUsage()
-{
- m_hasBeenUsedRecently = false;
-}
-
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_DATAGRAM_FACE_HPP
diff --git a/daemon/face/datagram-transport.hpp b/daemon/face/datagram-transport.hpp
new file mode 100644
index 0000000..f9cf2fc
--- /dev/null
+++ b/daemon/face/datagram-transport.hpp
@@ -0,0 +1,239 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
+#define NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
+
+#include "transport.hpp"
+#include "core/global-io.hpp"
+
+#include <array>
+
+namespace nfd {
+namespace face {
+
+struct Unicast {};
+struct Multicast {};
+
+/** \brief Implements Transport for datagram-based protocols.
+ *
+ * \tparam Protocol a datagram-based protocol in Boost.Asio
+ */
+template<class Protocol, class Addressing = Unicast>
+class DatagramTransport : public Transport
+{
+public:
+ typedef Protocol protocol;
+
+ /** \brief Construct datagram transport.
+ *
+ * \param socket Protocol-specific socket for the created transport
+ */
+ explicit
+ DatagramTransport(typename protocol::socket&& socket);
+
+ virtual void
+ doSend(Transport::Packet&& packet) DECL_OVERRIDE;
+
+ virtual void
+ doClose() DECL_OVERRIDE;
+
+ /** \brief Receive datagram, translate buffer into packet, deliver to parent class.
+ */
+ void
+ receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
+ const boost::system::error_code& error);
+
+protected:
+ void
+ handleReceive(const boost::system::error_code& error,
+ size_t nBytesReceived);
+
+ void
+ handleSend(const boost::system::error_code& error,
+ size_t nBytesSent, const Block& payload);
+
+ void
+ processErrorCode(const boost::system::error_code& error);
+
+ bool
+ hasBeenUsedRecently() const;
+
+ void
+ resetRecentUsage();
+
+protected:
+ typename protocol::socket m_socket;
+
+ NFD_LOG_INCLASS_DECLARE();
+
+private:
+ std::array<uint8_t, ndn::MAX_NDN_PACKET_SIZE> m_receiveBuffer;
+ bool m_hasBeenUsedRecently;
+};
+
+
+template<class T, class U>
+inline
+DatagramTransport<T, U>::DatagramTransport(typename DatagramTransport::protocol::socket&& socket)
+ : m_socket(std::move(socket))
+{
+ m_socket.async_receive(boost::asio::buffer(m_receiveBuffer),
+ bind(&DatagramTransport<T, U>::handleReceive, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ m_socket.async_send(boost::asio::buffer(packet.packet),
+ bind(&DatagramTransport<T, U>::handleSend, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred,
+ packet.packet));
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::doClose()
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ if (m_socket.is_open()) {
+ // Cancel all outstanding operations and close the socket.
+ // Use the non-throwing variants and ignore errors, if any.
+ boost::system::error_code error;
+ m_socket.cancel(error);
+ m_socket.close(error);
+ }
+
+ // Ensure that the Transport stays alive at least until
+ // all pending handlers are dispatched
+ getGlobalIoService().post([this] {
+ this->setState(TransportState::CLOSED);
+ });
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
+ const boost::system::error_code& error)
+{
+ if (error)
+ return processErrorCode(error);
+
+ NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
+
+ bool isOk = false;
+ Block element;
+ std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
+ if (!isOk) {
+ NFD_LOG_FACE_WARN("Failed to parse incoming packet");
+ // This packet won't extend the face lifetime
+ return;
+ }
+ if (element.size() != nBytesReceived) {
+ NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
+ // This packet won't extend the face lifetime
+ return;
+ }
+
+ m_hasBeenUsedRecently = true;
+ this->receive(Transport::Packet(std::move(element)));
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error,
+ size_t nBytesReceived)
+{
+ receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
+
+ if (m_socket.is_open())
+ m_socket.async_receive(boost::asio::buffer(m_receiveBuffer),
+ bind(&DatagramTransport<T, U>::handleReceive, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::handleSend(const boost::system::error_code& error,
+ size_t nBytesSent, const Block& payload)
+// 'payload' is unused; it's needed to retain the underlying Buffer
+{
+ if (error)
+ return processErrorCode(error);
+
+ NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error)
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ if (getState() == TransportState::CLOSING ||
+ getState() == TransportState::FAILED ||
+ getState() == TransportState::CLOSED ||
+ error == boost::asio::error::operation_aborted)
+ // transport is shutting down, ignore any errors
+ return;
+
+ if (getPersistency() == ndn::nfd::FacePersistency::FACE_PERSISTENCY_PERMANENT) {
+ NFD_LOG_FACE_DEBUG("Permanent face ignores error: " << error.message());
+ return;
+ }
+
+ if (error != boost::asio::error::eof)
+ NFD_LOG_FACE_WARN("Send or receive operation failed: " << error.message());
+
+ this->setState(TransportState::FAILED);
+ doClose();
+}
+
+template<class T, class U>
+inline bool
+DatagramTransport<T, U>::hasBeenUsedRecently() const
+{
+ return m_hasBeenUsedRecently;
+}
+
+template<class T, class U>
+inline void
+DatagramTransport<T, U>::resetRecentUsage()
+{
+ m_hasBeenUsedRecently = false;
+}
+
+} // namespace face
+} // namespace nfd
+
+#endif // NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
diff --git a/daemon/face/multicast-udp-face.cpp b/daemon/face/multicast-udp-face.cpp
deleted file mode 100644
index 8ac07af..0000000
--- a/daemon/face/multicast-udp-face.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "multicast-udp-face.hpp"
-
-namespace nfd {
-
-NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace,
- MulticastUdpFace::protocol, Multicast,
- "MulticastUdpFace");
-
-MulticastUdpFace::MulticastUdpFace(const protocol::endpoint& multicastGroup,
- const FaceUri& localUri,
- protocol::socket recvSocket, protocol::socket sendSocket)
- : DatagramFace(FaceUri(multicastGroup), localUri, std::move(recvSocket))
- , m_multicastGroup(multicastGroup)
- , m_sendSocket(std::move(sendSocket))
-{
-}
-
-const MulticastUdpFace::protocol::endpoint&
-MulticastUdpFace::getMulticastGroup() const
-{
- return m_multicastGroup;
-}
-
-void
-MulticastUdpFace::sendInterest(const Interest& interest)
-{
- NFD_LOG_FACE_TRACE(__func__);
- this->emitSignal(onSendInterest, interest);
- sendBlock(interest.wireEncode());
-}
-
-void
-MulticastUdpFace::sendData(const Data& data)
-{
- NFD_LOG_FACE_TRACE(__func__);
- /// \todo After this face implements duplicate suppression, onSendData should
- /// be emitted only when data is actually sent out. See also #2555
- this->emitSignal(onSendData, data);
- sendBlock(data.wireEncode());
-}
-
-void
-MulticastUdpFace::sendBlock(const Block& block)
-{
- m_sendSocket.async_send_to(boost::asio::buffer(block.wire(), block.size()), m_multicastGroup,
- bind(&MulticastUdpFace::handleSend, this,
- boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred,
- block));
-}
-
-} // namespace nfd
diff --git a/daemon/face/multicast-udp-face.hpp b/daemon/face/multicast-udp-face.hpp
deleted file mode 100644
index 7aab4a7..0000000
--- a/daemon/face/multicast-udp-face.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NFD_DAEMON_FACE_MULTICAST_UDP_FACE_HPP
-#define NFD_DAEMON_FACE_MULTICAST_UDP_FACE_HPP
-
-#include "datagram-face.hpp"
-
-namespace nfd {
-
-/**
- * \brief Implementation of Face abstraction that uses
- * multicast UDP as underlying transport mechanism
- */
-class MulticastUdpFace : public DatagramFace<boost::asio::ip::udp, Multicast>
-{
-public:
- /**
- * \brief Creates a UDP-based face for multicast communication
- */
- MulticastUdpFace(const protocol::endpoint& multicastGroup, const FaceUri& localUri,
- protocol::socket recvSocket, protocol::socket sendSocket);
-
- const protocol::endpoint&
- getMulticastGroup() const;
-
- // from Face
- void
- sendInterest(const Interest& interest) DECL_OVERRIDE;
-
- void
- sendData(const Data& data) DECL_OVERRIDE;
-
-private:
- void
- sendBlock(const Block& block);
-
-private:
- protocol::endpoint m_multicastGroup;
- protocol::socket m_sendSocket;
-};
-
-} // namespace nfd
-
-#endif // NFD_DAEMON_FACE_MULTICAST_UDP_FACE_HPP
diff --git a/daemon/face/multicast-udp-transport.cpp b/daemon/face/multicast-udp-transport.cpp
new file mode 100644
index 0000000..7befa78
--- /dev/null
+++ b/daemon/face/multicast-udp-transport.cpp
@@ -0,0 +1,79 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "multicast-udp-transport.hpp"
+
+namespace nfd {
+namespace face {
+
+NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(DatagramTransport, MulticastUdpTransport::protocol,
+ Multicast, "MulticastUdpTransport");
+
+MulticastUdpTransport::MulticastUdpTransport(const protocol::endpoint& localEndpoint,
+ const protocol::endpoint& multicastGroup,
+ protocol::socket&& recvSocket,
+ protocol::socket&& sendSocket)
+ : DatagramTransport(std::move(recvSocket))
+ , m_multicastGroup(multicastGroup)
+ , m_sendSocket(std::move(sendSocket))
+{
+ this->setLocalUri(FaceUri(localEndpoint));
+ this->setRemoteUri(FaceUri(multicastGroup));
+ this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+ this->setLinkType(ndn::nfd::LINK_TYPE_MULTI_ACCESS);
+
+ NFD_LOG_FACE_INFO("Creating transport");
+}
+
+void
+MulticastUdpTransport::doSend(Transport::Packet&& packet)
+{
+ NFD_LOG_FACE_TRACE(__func__);
+
+ m_sendSocket.async_send_to(boost::asio::buffer(packet.packet), m_multicastGroup,
+ bind(&MulticastUdpTransport::handleSend, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred,
+ packet.packet));
+}
+
+void
+MulticastUdpTransport::doClose()
+{
+ if (m_sendSocket.is_open()) {
+ NFD_LOG_FACE_TRACE("Closing sending socket");
+
+ // Cancel all outstanding operations and close the socket.
+ // Use the non-throwing variants and ignore errors, if any.
+ boost::system::error_code error;
+ m_sendSocket.cancel(error);
+ m_sendSocket.close(error);
+ }
+
+ DatagramTransport::doClose();
+}
+
+} // namespace face
+} // namespace nfd
diff --git a/daemon/face/multicast-udp-transport.hpp b/daemon/face/multicast-udp-transport.hpp
new file mode 100644
index 0000000..7966b5b
--- /dev/null
+++ b/daemon/face/multicast-udp-transport.hpp
@@ -0,0 +1,64 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FACE_MULTICAST_UDP_TRANSPORT_HPP
+#define NFD_DAEMON_FACE_MULTICAST_UDP_TRANSPORT_HPP
+
+#include "datagram-transport.hpp"
+
+namespace nfd {
+namespace face {
+
+/**
+ * \brief A Transport that communicates on a UDP multicast group
+ */
+class MulticastUdpTransport : public DatagramTransport<boost::asio::ip::udp, Multicast>
+{
+public:
+ /**
+ * \brief Creates a UDP-based transport for multicast communication
+ * \param recvSocket socket used to receive packets
+ * \param sendSocket socket used to send to the multicast address
+ */
+ MulticastUdpTransport(const protocol::endpoint& localEndpoint,
+ const protocol::endpoint& multicastGroup,
+ protocol::socket&& recvSocket, protocol::socket&& sendSocket);
+
+private:
+ virtual void
+ doSend(Transport::Packet&& packet) DECL_OVERRIDE;
+
+ virtual void
+ doClose() DECL_OVERRIDE;
+
+private:
+ protocol::endpoint m_multicastGroup;
+ protocol::socket m_sendSocket;
+};
+
+} // namespace face
+} // namespace nfd
+
+#endif // NFD_DAEMON_FACE_MULTICAST_UDP_TRANSPORT_HPP
diff --git a/daemon/face/udp-channel.cpp b/daemon/face/udp-channel.cpp
index c9920c4..a1ff92c 100644
--- a/daemon/face/udp-channel.cpp
+++ b/daemon/face/udp-channel.cpp
@@ -24,7 +24,8 @@
*/
#include "udp-channel.hpp"
-#include "udp-face.hpp"
+#include "generic-link-service.hpp"
+#include "unicast-udp-transport.hpp"
#include "core/global-io.hpp"
namespace nfd {
@@ -71,7 +72,7 @@
const FaceCreatedCallback& onFaceCreated,
const ConnectFailedCallback& onConnectFailed)
{
- shared_ptr<UdpFace> face;
+ shared_ptr<face::LpFaceWrapper> face;
try {
face = createFace(remoteEndpoint, persistency).second;
}
@@ -93,7 +94,7 @@
return m_channelFaces.size();
}
-std::pair<bool, shared_ptr<UdpFace>>
+std::pair<bool, shared_ptr<face::LpFaceWrapper>>
UdpChannel::createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency)
{
auto it = m_channelFaces.find(remoteEndpoint);
@@ -116,15 +117,18 @@
socket.bind(m_localEndpoint);
socket.connect(remoteEndpoint);
- auto face = make_shared<UdpFace>(FaceUri(remoteEndpoint), FaceUri(m_localEndpoint),
- std::move(socket), persistency, m_idleFaceTimeout);
+ auto linkService = make_unique<face::GenericLinkService>();
+ auto transport = make_unique<face::UnicastUdpTransport>(std::move(socket), persistency, m_idleFaceTimeout);
+ auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
+ auto face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
+ face->setPersistency(persistency);
face->onFail.connectSingleShot([this, remoteEndpoint] (const std::string&) {
NFD_LOG_TRACE("Erasing " << remoteEndpoint << " from channel face map");
m_channelFaces.erase(remoteEndpoint);
});
- m_channelFaces[remoteEndpoint] = face;
+ m_channelFaces[remoteEndpoint] = face;
return {true, face};
}
@@ -147,7 +151,7 @@
NFD_LOG_DEBUG("[" << m_localEndpoint << "] New peer " << m_remoteEndpoint);
bool created;
- shared_ptr<UdpFace> face;
+ shared_ptr<face::LpFaceWrapper> face;
try {
std::tie(created, face) = createFace(m_remoteEndpoint, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
}
@@ -163,7 +167,7 @@
onFaceCreated(face);
// dispatch the datagram to the face for processing
- face->receiveDatagram(m_inputBuffer, nBytesReceived, error);
+ static_cast<face::UnicastUdpTransport*>(face->getLpFace()->getTransport())->receiveDatagram(m_inputBuffer, nBytesReceived, error);
m_socket.async_receive_from(boost::asio::buffer(m_inputBuffer, ndn::MAX_NDN_PACKET_SIZE),
m_remoteEndpoint,
diff --git a/daemon/face/udp-channel.hpp b/daemon/face/udp-channel.hpp
index 3f92ada..0825ad4 100644
--- a/daemon/face/udp-channel.hpp
+++ b/daemon/face/udp-channel.hpp
@@ -1,12 +1,12 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2014, Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology,
- * The University of Memphis
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
*
* This file is part of NFD (Named Data Networking Forwarding Daemon).
* See AUTHORS.md for complete list of NFD authors and contributors.
@@ -27,6 +27,7 @@
#define NFD_DAEMON_FACE_UDP_CHANNEL_HPP
#include "channel.hpp"
+#include "lp-face-wrapper.hpp"
namespace nfd {
@@ -34,8 +35,6 @@
typedef boost::asio::ip::udp::endpoint Endpoint;
} // namespace udp
-class UdpFace;
-
/**
* \brief Class implementing UDP-based channel to create faces
*/
@@ -92,7 +91,7 @@
isListening() const;
private:
- std::pair<bool, shared_ptr<UdpFace>>
+ std::pair<bool, shared_ptr<face::LpFaceWrapper>>
createFace(const udp::Endpoint& remoteEndpoint, ndn::nfd::FacePersistency persistency);
/**
@@ -106,7 +105,7 @@
const ConnectFailedCallback& onReceiveFailed);
private:
- std::map<udp::Endpoint, shared_ptr<UdpFace>> m_channelFaces;
+ std::map<udp::Endpoint, shared_ptr<face::LpFaceWrapper>> m_channelFaces;
udp::Endpoint m_localEndpoint;
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index 8d24bbe..74636d8 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -24,6 +24,9 @@
*/
#include "udp-factory.hpp"
+#include "generic-link-service.hpp"
+#include "lp-face-wrapper.hpp"
+#include "multicast-udp-transport.hpp"
#include "core/global-io.hpp"
#include "core/network-interface.hpp"
@@ -117,11 +120,12 @@
if (static_cast<bool>(channel))
return channel;
- //checking if the endpoint is already in use for multicast face
- shared_ptr<MulticastUdpFace> multicast = findMulticastFace(endpoint);
- if (static_cast<bool>(multicast))
+ // check if the endpoint is already used by a multicast face
+ auto face = findMulticastFace(endpoint);
+ if (face) {
BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP unicast channel, local "
"endpoint is already allocated for a UDP multicast face"));
+ }
if (endpoint.address().is_multicast()) {
BOOST_THROW_EXCEPTION(Error("This method is only for unicast channel. The provided "
@@ -146,15 +150,15 @@
return createChannel(endpoint, timeout);
}
-shared_ptr<MulticastUdpFace>
+shared_ptr<face::LpFaceWrapper>
UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
const udp::Endpoint& multicastEndpoint,
const std::string& networkInterfaceName/* = ""*/)
{
// checking if the local and multicast endpoints are already in use for a multicast face
- shared_ptr<MulticastUdpFace> face = findMulticastFace(localEndpoint);
- if (static_cast<bool>(face)) {
- if (face->getMulticastGroup() == multicastEndpoint)
+ auto face = findMulticastFace(localEndpoint);
+ if (face) {
+ if (face->getRemoteUri() == FaceUri(multicastEndpoint))
return face;
else
BOOST_THROW_EXCEPTION(Error("Cannot create the requested UDP multicast face, local "
@@ -225,8 +229,12 @@
}
#endif
- face = make_shared<MulticastUdpFace>(multicastEndpoint, FaceUri(localEndpoint),
- std::move(receiveSocket), std::move(sendSocket));
+ auto linkService = make_unique<face::GenericLinkService>();
+ auto transport = make_unique<face::MulticastUdpTransport>(localEndpoint, multicastEndpoint,
+ std::move(receiveSocket),
+ std::move(sendSocket));
+ auto lpFace = make_unique<face::LpFace>(std::move(linkService), std::move(transport));
+ face = make_shared<face::LpFaceWrapper>(std::move(lpFace));
face->onFail.connectSingleShot([this, localEndpoint] (const std::string& reason) {
m_multicastFaces.erase(localEndpoint);
@@ -236,7 +244,7 @@
return face;
}
-shared_ptr<MulticastUdpFace>
+shared_ptr<face::LpFaceWrapper>
UdpFactory::createMulticastFace(const std::string& localIp,
const std::string& multicastIp,
const std::string& multicastPort,
@@ -302,14 +310,14 @@
return shared_ptr<UdpChannel>();
}
-shared_ptr<MulticastUdpFace>
+shared_ptr<face::LpFaceWrapper>
UdpFactory::findMulticastFace(const udp::Endpoint& localEndpoint)
{
MulticastFaceMap::iterator i = m_multicastFaces.find(localEndpoint);
if (i != m_multicastFaces.end())
return i->second;
else
- return shared_ptr<MulticastUdpFace>();
+ return nullptr;
}
std::list<shared_ptr<const Channel>>
diff --git a/daemon/face/udp-factory.hpp b/daemon/face/udp-factory.hpp
index 1a3714c..0465ca5 100644
--- a/daemon/face/udp-factory.hpp
+++ b/daemon/face/udp-factory.hpp
@@ -28,7 +28,6 @@
#include "protocol-factory.hpp"
#include "udp-channel.hpp"
-#include "multicast-udp-face.hpp"
namespace nfd {
@@ -50,7 +49,7 @@
}
};
- typedef std::map<udp::Endpoint, shared_ptr<MulticastUdpFace>> MulticastFaceMap;
+ typedef std::map<udp::Endpoint, shared_ptr<face::LpFaceWrapper>> MulticastFaceMap;
explicit
UdpFactory(const std::string& defaultPort = "6363");
@@ -131,12 +130,12 @@
* \see http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/ip__udp/endpoint.html
* for details on ways to create udp::Endpoint
*/
- shared_ptr<MulticastUdpFace>
+ shared_ptr<face::LpFaceWrapper>
createMulticastFace(const udp::Endpoint& localEndpoint,
const udp::Endpoint& multicastEndpoint,
const std::string& networkInterfaceName = "");
- shared_ptr<MulticastUdpFace>
+ shared_ptr<face::LpFaceWrapper>
createMulticastFace(const std::string& localIp,
const std::string& multicastIp,
const std::string& multicastPort,
@@ -186,11 +185,9 @@
* \brief Look up multicast UdpFace using specified local endpoint
*
* \returns shared pointer to the existing multicast MulticastUdpFace object
- * or empty shared pointer when such face does not exist
- *
- * \throws never
+ * or nullptr when such face does not exist
*/
- shared_ptr<MulticastUdpFace>
+ shared_ptr<face::LpFaceWrapper>
findMulticastFace(const udp::Endpoint& localEndpoint);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
diff --git a/daemon/face/udp-face.cpp b/daemon/face/unicast-udp-transport.cpp
similarity index 63%
rename from daemon/face/udp-face.cpp
rename to daemon/face/unicast-udp-transport.cpp
index 6985784..eb8ab66 100644
--- a/daemon/face/udp-face.cpp
+++ b/daemon/face/unicast-udp-transport.cpp
@@ -23,8 +23,7 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "udp-face.hpp"
-// #include "core/global-io.hpp" // for #1718 manual test below
+#include "unicast-udp-transport.hpp"
#ifdef __linux__
#include <cerrno> // for errno
@@ -34,17 +33,24 @@
#endif
namespace nfd {
+namespace face {
-NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramFace, UdpFace::protocol, "UdpFace");
+NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(DatagramTransport, UnicastUdpTransport::protocol,
+ "UnicastUdpTransport");
-UdpFace::UdpFace(const FaceUri& remoteUri, const FaceUri& localUri,
- protocol::socket socket, ndn::nfd::FacePersistency persistency,
- const time::seconds& idleTimeout)
- : DatagramFace(remoteUri, localUri, std::move(socket))
+UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
+ ndn::nfd::FacePersistency persistency,
+ const time::seconds& idleTimeout)
+ : DatagramTransport(std::move(socket))
, m_idleTimeout(idleTimeout)
, m_lastIdleCheck(time::steady_clock::now())
{
+ this->setLocalUri(FaceUri(m_socket.local_endpoint()));
+ this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
this->setPersistency(persistency);
+ this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
+
+ NFD_LOG_FACE_INFO("Creating transport");
#ifdef __linux__
//
@@ -66,56 +72,31 @@
}
#endif
- if (this->getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND && m_idleTimeout > time::seconds::zero()) {
- m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UdpFace::closeIfIdle, this));
+ if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
+ m_idleTimeout > time::seconds::zero()) {
+ m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UnicastUdpTransport::closeIfIdle, this));
}
}
-ndn::nfd::FaceStatus
-UdpFace::getFaceStatus() const
-{
- auto status = DatagramFace::getFaceStatus();
-
- if (this->getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
- time::milliseconds left = m_idleTimeout;
- left -= time::duration_cast<time::milliseconds>(time::steady_clock::now() - m_lastIdleCheck);
-
- if (left < time::milliseconds::zero())
- left = time::milliseconds::zero();
-
- if (hasBeenUsedRecently())
- left += m_idleTimeout;
-
- status.setExpirationPeriod(left);
- }
-
- return status;
-}
-
void
-UdpFace::closeIfIdle()
+UnicastUdpTransport::closeIfIdle()
{
- // Face can be switched from on-demand to non-on-demand mode
+ // transport can be switched from on-demand to non-on-demand mode
// (non-on-demand -> on-demand transition is not allowed)
- if (this->getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
+ if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND) {
if (!hasBeenUsedRecently()) {
- NFD_LOG_FACE_INFO("Closing for inactivity");
- close();
-
- // #1718 manual test: uncomment, run NFD in valgrind, send in a UDP packet
- // expect read-after-free error and crash
- // getGlobalIoService().post([this] {
- // NFD_LOG_FACE_ERROR("Remaining references: " << this->shared_from_this().use_count());
- // });
+ NFD_LOG_FACE_INFO("Closing due to inactivity");
+ this->close();
}
else {
resetRecentUsage();
m_lastIdleCheck = time::steady_clock::now();
- m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UdpFace::closeIfIdle, this));
+ m_closeIfIdleEvent = scheduler::schedule(m_idleTimeout, bind(&UnicastUdpTransport::closeIfIdle, this));
}
}
// else do nothing and do not reschedule the event
}
+} // namespace face
} // namespace nfd
diff --git a/daemon/face/udp-face.hpp b/daemon/face/unicast-udp-transport.hpp
similarity index 70%
rename from daemon/face/udp-face.hpp
rename to daemon/face/unicast-udp-transport.hpp
index a7541a5..2622e4b 100644
--- a/daemon/face/udp-face.hpp
+++ b/daemon/face/unicast-udp-transport.hpp
@@ -23,27 +23,24 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef NFD_DAEMON_FACE_UDP_FACE_HPP
-#define NFD_DAEMON_FACE_UDP_FACE_HPP
+#ifndef NFD_DAEMON_FACE_UDP_TRANSPORT_HPP
+#define NFD_DAEMON_FACE_UDP_TRANSPORT_HPP
-#include "datagram-face.hpp"
+#include "datagram-transport.hpp"
#include "core/scheduler.hpp"
namespace nfd {
+namespace face {
/**
- * \brief Implementation of Face abstraction that uses
- * unicast UDP as underlying transport mechanism
+ * \brief A Transport that communicates on a unicast UDP socket
*/
-class UdpFace : public DatagramFace<boost::asio::ip::udp>
+class UnicastUdpTransport : public DatagramTransport<boost::asio::ip::udp>
{
public:
- UdpFace(const FaceUri& remoteUri, const FaceUri& localUri,
- protocol::socket socket, ndn::nfd::FacePersistency persistency,
- const time::seconds& idleTimeout);
-
- ndn::nfd::FaceStatus
- getFaceStatus() const DECL_OVERRIDE;
+ UnicastUdpTransport(protocol::socket&& socket,
+ ndn::nfd::FacePersistency persistency,
+ const time::seconds& idleTimeout);
private:
void
@@ -53,11 +50,9 @@
const time::seconds m_idleTimeout;
time::steady_clock::TimePoint m_lastIdleCheck;
scheduler::ScopedEventId m_closeIfIdleEvent;
-
- // friend because it needs to invoke protected Face::setOnDemand
- friend class UdpChannel;
};
+} // namespace face
} // namespace nfd
-#endif // NFD_DAEMON_FACE_UDP_FACE_HPP
+#endif // NFD_DAEMON_FACE_UDP_TRANSPORT_HPP
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 2991ee6..b49b752 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -26,9 +26,10 @@
#include "face-manager.hpp"
#include "core/network-interface.hpp"
-#include "fw/face-table.hpp"
+#include "face/lp-face-wrapper.hpp"
#include "face/tcp-factory.hpp"
#include "face/udp-factory.hpp"
+#include "fw/face-table.hpp"
#include <ndn-cxx/management/nfd-face-status.hpp>
#include <ndn-cxx/management/nfd-channel-status.hpp>
@@ -685,7 +686,7 @@
}
#endif
- std::list<shared_ptr<MulticastUdpFace> > multicastFacesToRemove;
+ std::list<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
for (auto i = factory->getMulticastFaces().begin();
i != factory->getMulticastFaces().end();
++i) {
@@ -693,33 +694,27 @@
}
for (const auto& nic : ipv4MulticastInterfaces) {
- shared_ptr<MulticastUdpFace> newFace;
- newFace = factory->createMulticastFace(nic.ipv4Addresses[0].to_string(),
- mcastGroup,
- mcastPort,
- isNicNameNecessary ? nic.name : "");
+ auto newFace = factory->createMulticastFace(nic.ipv4Addresses[0].to_string(),
+ mcastGroup, mcastPort,
+ isNicNameNecessary ? nic.name : "");
addCreatedFaceToForwarder(newFace);
multicastFacesToRemove.remove(newFace);
}
- for (auto i = multicastFacesToRemove.begin();
- i != multicastFacesToRemove.end();
- ++i) {
- (*i)->close();
+ for (const auto& face : multicastFacesToRemove) {
+ face->close();
}
}
else {
- std::list<shared_ptr<MulticastUdpFace>> multicastFacesToRemove;
+ std::list<shared_ptr<face::LpFaceWrapper>> multicastFacesToRemove;
for (auto i = factory->getMulticastFaces().begin();
i != factory->getMulticastFaces().end();
++i) {
multicastFacesToRemove.push_back(i->second);
}
- for (auto i = multicastFacesToRemove.begin();
- i != multicastFacesToRemove.end();
- ++i) {
- (*i)->close();
+ for (const auto& face : multicastFacesToRemove) {
+ face->close();
}
}
}