blob: c490e07fd4915d4ffccbec4e15817a7f5652f75a [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2022, 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_PROTOCOL_FACTORY_HPP
#define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
#include "channel.hpp"
#include "face.hpp"
#include "face-system.hpp"
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd::face {
/**
* \brief Parameters to ProtocolFactory constructor.
*
* Every ProtocolFactory subclass is expected to have a constructor that accepts
* ProtocolFactory::CtorParams, which in turn passes it to ProtocolFactory base class
* constructor. Parameters are passed as a struct rather than individually, so that
* any future changes in the list of parameters will not require updates to all subclass
* constructors.
*/
struct ProtocolFactoryCtorParams
{
FaceCreatedCallback addFace;
shared_ptr<ndn::net::NetworkMonitor> netmon;
};
/**
* \brief Provides support for an underlying protocol.
*
* A protocol factory provides support for an underlying protocol and owns Channel objects.
* It can process a subsection of the `face_system` configuration section and create channels
* and multicast faces accordingly.
*
* \sa FaceSystem
*/
class ProtocolFactory : noncopyable
{
public: // registry
using CtorParams = ProtocolFactoryCtorParams;
/**
* \brief Register a protocol factory type.
* \tparam PF subclass of ProtocolFactory
* \param id factory identifier
*/
template<typename PF>
static void
registerType(const std::string& id = PF::getId())
{
BOOST_ASSERT(!id.empty());
auto r = getRegistry().insert_or_assign(id, [] (auto&&... p) {
return make_unique<PF>(std::forward<decltype(p)>(p)...);
});
BOOST_VERIFY(r.second);
}
/**
* \brief Create a protocol factory instance.
* \retval nullptr if a factory with the given \p id is not registered
*/
static unique_ptr<ProtocolFactory>
create(const std::string& id, const CtorParams& params);
/**
* \brief Get all registered protocol factory IDs.
*/
[[nodiscard]] static std::set<std::string>
listRegistered();
public:
/**
* \brief Base class for all exceptions thrown by ProtocolFactory subclasses.
*/
class Error : public std::runtime_error
{
public:
using std::runtime_error::runtime_error;
};
explicit
ProtocolFactory(const CtorParams& params);
virtual
~ProtocolFactory() = 0;
#ifdef DOXYGEN
/**
* \brief Get the ID of this protocol factory.
*
* `face_system.<factory-id>` config section is processed by the protocol factory.
*/
static const std::string&
getId() noexcept;
#endif
/**
* \brief Get FaceUri schemes accepted by this protocol factory.
*/
const std::set<std::string>&
getProvidedSchemes() const noexcept
{
return providedSchemes;
}
/** \brief Process face_system subsection that corresponds to this protocol factory id
* \param configSection the configuration section or boost::none to indicate it is omitted
* \param context provides access to data structures and contextual information
* \throw ConfigFile::Error invalid configuration
*/
void
processConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext& context);
/** \brief Encapsulates a face creation request and all its parameters
*
* Parameters are passed as a struct rather than individually, so that a future change in the list
* of parameters does not require an update to the method signature in all subclasses.
*/
struct CreateFaceRequest
{
FaceUri remoteUri;
std::optional<FaceUri> localUri;
FaceParams params;
};
/** \brief Create a unicast face
* \param req request object containing the face creation parameters
* \param onCreated callback if face creation succeeds or face already exists; the settings
* of an existing face are not updated if they differ from the request
* \param onFailure callback if face creation fails
*/
void
createFace(const CreateFaceRequest& req,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure);
/** \brief Create a netdev-bound face
* \param remote remote FaceUri, must be canonical
* \param netdev local network interface
* \return new face
* \throw Error cannot create a face using specified arguments
* \note The caller must ensure there is no existing netdev-bound face with same remote FaceUri
* on the same local network interface.
*/
shared_ptr<Face>
createNetdevBoundFace(const FaceUri& remote,
const shared_ptr<const ndn::net::NetworkInterface>& netdev);
/** \brief Get list of open channels (listening + non-listening)
*/
std::vector<shared_ptr<const Channel>>
getChannels() const;
protected:
template<typename ChannelMap>
static std::vector<shared_ptr<const Channel>>
getChannelsFromMap(const ChannelMap& channelMap)
{
std::vector<shared_ptr<const Channel>> channels;
boost::copy(channelMap | boost::adaptors::map_values, std::back_inserter(channels));
return channels;
}
private:
/** \brief Process face_system subsection that corresponds to this protocol factory id
* \sa processConfig
*
* A subclass should override this method if it supports configuration options in the config
* file, and do all the required processing here. The subclass should throw ConfigFile::Error
* if it encounters unrecognized options or invalid values. It should also update
* \p providedSchemes as needed.
*
* The base class implementation does nothing.
*/
virtual void
doProcessConfig(OptionalConfigSection configSection, FaceSystem::ConfigContext& context);
/** \brief Create a unicast face
* \sa createFace
*
* The base class implementation always invokes the failure callback with error code 406,
* indicating unicast face creation is not supported.
*/
virtual void
doCreateFace(const CreateFaceRequest& req,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure);
/** \brief Create a netdev-bound face
* \sa createNetdevBoundFace
*
* The base class implementation always throws Error, indicating netdev-bound faces are not
* supported.
*
* A subclass that offers netdev-bound faces should override this method, and also expose
* "scheme+dev" in providedSchemes. For example, UdpFactory should provide "udp4+dev" scheme,
* in addition to "udp4" scheme.
*
* The face should be constructed immediately. Face persistency shall be reported as PERMANENT.
* Face state shall remain DOWN until underlying transport is connected. The face shall remain
* open until after .close() is invoked, and survive all socket errors; in case the network
* interface disappears, the face shall remain DOWN until .close() is invoked.
*/
virtual shared_ptr<Face>
doCreateNetdevBoundFace(const FaceUri& remote,
const shared_ptr<const ndn::net::NetworkInterface>& netif);
/** \brief Get list of open channels (listening + non-listening)
* \sa getChannels
*
* The base class implementation returns an empty list.
*/
virtual std::vector<shared_ptr<const Channel>>
doGetChannels() const;
private: // registry
using CreateFunc = std::function<unique_ptr<ProtocolFactory>(const CtorParams&)>;
using Registry = std::map<std::string, CreateFunc>; // indexed by factory id
static Registry&
getRegistry();
protected:
std::set<std::string> providedSchemes; ///< FaceUri schemes provided by this protocol factory
FaceCreatedCallback addFace; ///< callback when a new face is created
/** \brief NetworkMonitor for listing available network interfaces and monitoring their changes
*
* ProtocolFactory subclass should check the NetworkMonitor has sufficient capabilities prior
* to usage.
*/
shared_ptr<ndn::net::NetworkMonitor> netmon;
};
} // namespace nfd::face
/** \brief Registers a protocol factory
*
* This macro should appear once in the .cpp file of each protocol factory.
*/
#define NFD_REGISTER_PROTOCOL_FACTORY(PF) \
static class NfdAuto ## PF ## ProtocolFactoryRegistrationClass \
{ \
public: \
NfdAuto ## PF ## ProtocolFactoryRegistrationClass() \
{ \
::nfd::face::ProtocolFactory::registerType<PF>(); \
} \
} g_nfdAuto ## PF ## ProtocolFactoryRegistrationVariable
#endif // NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP