diff --git a/asyncmsg/NameService.h b/asyncmsg/NameService.h index 26fbabba76abdb16374e9cb261b7ea2b8b135600..170abbba6973e85c4fe971105a4431a6e4be5ceb 100644 --- a/asyncmsg/NameService.h +++ b/asyncmsg/NameService.h @@ -41,6 +41,13 @@ namespace daq { ((std::string)m_name) ) + ERS_DECLARE_ISSUE_BASE(asyncmsg, + CannotAllocateMulticast, + Issue, + "Cannot allocate multicast address", + ERS_EMPTY, + ERS_EMPTY) + namespace asyncmsg { @@ -106,16 +113,42 @@ namespace daq { /** \brief Resolve a single specific application. * - * \param[in] Resolves exactly one specific remote applications. + * \param[in] name Resolves exactly one specific remote applications with this name. * * \throws daq::asyncmsg::CannotResolve, IS exceptions */ boost::asio::ip::tcp::endpoint resolve(const std::string& name) const; - /** \brief A helper method to parse a string of the form network/netmask. + /** + * \brief Allocate the multicast address for the partition. + * + * \param[in] addr The string representation of the address; can be a full IP address or '*'. + * \param[in] network The string representation of the network to use for multicast. + * \returns The allocated multicast address. + * \throws daq::asyncmsg::CannotAllocateMulticast, daq::asyncmsg::InvalidISServer + * + * Only one application per partition should call this. If the 'addr' parameter contains + * a '*', the multicast address will be dynamically allocated in such a way that it + * is unique per installation and across partitions (e.g. in Point 1). + */ + std::string allocate_multicast_address(const std::string& addr, const std::string& network); + + /** \brief Find the multicast address for the partition. * + * \returns A string containing the IP addresses usable by boost::asio. + * + * \throws daq::asyncmsg::CannotResolve + * + * Applications who need the multicast address of the partition should call this with the + * 'addr' taken from OKS. If 'addr' is '*' the multicast address will be dynamically looked up. */ + std::string lookup_multicast_address(const std::string& addr) const; + + /** typedef for readability, a 2-tuple of IP addresses representing network/netmask. */ typedef std::tuple<boost::asio::ip::address,boost::asio::ip::address> Network; + + /** \brief A helper method to parse a string of the form network/netmask. + */ static Network parse_address_network(const std::string& network); /** \brief A helper method to find the local interface matching netmask. diff --git a/schema/MsgInfo_is.schema.xml b/schema/MsgInfo_is.schema.xml index 7876424f70f662c93d9b54b39405e24158002628..a91496c5bddbf85c94f59f97d962baee03ee5cb6 100644 --- a/schema/MsgInfo_is.schema.xml +++ b/schema/MsgInfo_is.schema.xml @@ -9,7 +9,6 @@ <!ATTLIST info name CDATA #REQUIRED type CDATA #REQUIRED - num-of-includes CDATA #REQUIRED num-of-items CDATA #REQUIRED oks-format CDATA #FIXED "schema" oks-version CDATA #REQUIRED @@ -50,7 +49,6 @@ range CDATA "" format (dec|hex|oct) "dec" is-multi-value (yes|no) "no" - multi-value-implementation (list|vector) "list" init-value CDATA "" is-not-null (yes|no) "no" > @@ -64,7 +62,6 @@ is-composite (yes|no) #REQUIRED is-exclusive (yes|no) #REQUIRED is-dependent (yes|no) #REQUIRED - multi-value-implementation (list|vector) "list" > <!ELEMENT method (method-implementation*)> <!ATTLIST method @@ -81,7 +78,12 @@ <oks-schema> -<info name="" type="" num-of-includes="0" num-of-items="1" oks-format="schema" oks-version="oks-06-06-07 built "May 2 2013"" created-by="rhauser" created-on="msu-pc7.cern.ch" creation-time="20130502T084342" last-modified-by="rhauser" last-modified-on="msu-pc7.cern.ch" last-modification-time="20130502T084544"/> +<info name="" type="" num-of-items="2" oks-format="schema" oks-version="oks-06-09-02 built "Nov 2 2015"" created-by="rhauser" created-on="msu-pc7.cern.ch" creation-time="20130502T084342" last-modified-by="rhauser" last-modified-on="msu-pc7.cern.ch" last-modification-time="20151102T125421"/> + +<include> + <file path="is/is.xml"/> +</include> + <class name="MsgInfo"> <superclass name="Info"/> @@ -90,4 +92,11 @@ <attribute name="Port" description="Port number" type="u16" is-not-null="yes"/> </class> + <class name="MultiCastGroup"> + <superclass name="Info"/> + <attribute name="Partition" description="The name of the partition where this multicast group is used." type="string" is-not-null="yes"/> + <attribute name="MulticastAddress" description="The address of the multicast group. It must be in the 224.*.*.* range." type="string" range="224\.[0-9]+\.[0-9]+\.[0-9]+" init-value="224.200.100.100" is-not-null="yes"/> + <attribute name="MulticastNetwork" description="The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the " type="string" range="[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?" init-value="10.149.0.0" is-not-null="yes"/> + </class> + </oks-schema> diff --git a/src/MultiCastGroup.h b/src/MultiCastGroup.h new file mode 100644 index 0000000000000000000000000000000000000000..ea755561c5cd2239a4b263ffdf23f7642a5d4b22 --- /dev/null +++ b/src/MultiCastGroup.h @@ -0,0 +1,105 @@ +#ifndef MULTICASTGROUP_H +#define MULTICASTGROUP_H + +#include <is/info.h> + +#include <string> +#include <ostream> + + +// <<BeginUserCode>> + +// <<EndUserCode>> +/** + * + * @author generated by the IS tool + * @version 04/11/15 + */ + +class MultiCastGroup : public ISInfo { +public: + + /** + * The name of the partition where this multicast group is used. + */ + std::string Partition; + + /** + * The address of the multicast group. It must be in the 224.*.*.* range. + */ + std::string MulticastAddress; + + /** + * The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the + */ + std::string MulticastNetwork; + + + static const ISType & type() { + static const ISType type_ = MultiCastGroup( ).ISInfo::type(); + return type_; + } + + virtual std::ostream & print( std::ostream & out ) const { + ISInfo::print( out ); + out << std::endl; + out << "Partition: " << Partition << "\t// The name of the partition where this multicast group is used." << std::endl; + out << "MulticastAddress: " << MulticastAddress << "\t// The address of the multicast group. It must be in the 224.*.*.* range." << std::endl; + out << "MulticastNetwork: " << MulticastNetwork << "\t// The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the "; + return out; + } + + MultiCastGroup( ) + : ISInfo( "MultiCastGroup" ) + { + initialize(); + } + + ~MultiCastGroup(){ + +// <<BeginUserCode>> + +// <<EndUserCode>> + } + +protected: + MultiCastGroup( const std::string & type ) + : ISInfo( type ) + { + initialize(); + } + + void publishGuts( ISostream & out ){ + out << Partition << MulticastAddress << MulticastNetwork; + } + + void refreshGuts( ISistream & in ){ + in >> Partition >> MulticastAddress >> MulticastNetwork; + } + +private: + void initialize() + { + MulticastAddress = "224.200.100.100"; + MulticastNetwork = "10.149.0.0"; + +// <<BeginUserCode>> + +// <<EndUserCode>> + } + + +// <<BeginUserCode>> + +// <<EndUserCode>> +}; + +// <<BeginUserCode>> + +// <<EndUserCode>> +inline std::ostream & operator<<( std::ostream & out, const MultiCastGroup & info ) { + info.print( out ); + return out; +} + +#endif // MULTICASTGROUP_H diff --git a/src/MultiCastGroupNamed.h b/src/MultiCastGroupNamed.h new file mode 100644 index 0000000000000000000000000000000000000000..300b23803834a912caf3671257b7c7c6027a5dfc --- /dev/null +++ b/src/MultiCastGroupNamed.h @@ -0,0 +1,105 @@ +#ifndef MULTICASTGROUPNAMED_H +#define MULTICASTGROUPNAMED_H + +#include <is/namedinfo.h> + +#include <string> +#include <ostream> + + +// <<BeginUserCode>> + +// <<EndUserCode>> +/** + * + * @author generated by the IS tool + * @version 04/11/15 + */ + +class MultiCastGroupNamed : public ISNamedInfo { +public: + + /** + * The name of the partition where this multicast group is used. + */ + std::string Partition; + + /** + * The address of the multicast group. It must be in the 224.*.*.* range. + */ + std::string MulticastAddress; + + /** + * The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the + */ + std::string MulticastNetwork; + + + static const ISType & type() { + static const ISType type_ = MultiCastGroupNamed( IPCPartition(), "" ).ISInfo::type(); + return type_; + } + + virtual std::ostream & print( std::ostream & out ) const { + ISNamedInfo::print( out ); + out << std::endl; + out << "Partition: " << Partition << "\t// The name of the partition where this multicast group is used." << std::endl; + out << "MulticastAddress: " << MulticastAddress << "\t// The address of the multicast group. It must be in the 224.*.*.* range." << std::endl; + out << "MulticastNetwork: " << MulticastNetwork << "\t// The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the "; + return out; + } + + MultiCastGroupNamed( const IPCPartition & partition, const std::string & name ) + : ISNamedInfo( partition, name, "MultiCastGroup" ) + { + initialize(); + } + + ~MultiCastGroupNamed(){ + +// <<BeginUserCode>> + +// <<EndUserCode>> + } + +protected: + MultiCastGroupNamed( const IPCPartition & partition, const std::string & name, const std::string & type ) + : ISNamedInfo( partition, name, type ) + { + initialize(); + } + + void publishGuts( ISostream & out ){ + out << Partition << MulticastAddress << MulticastNetwork; + } + + void refreshGuts( ISistream & in ){ + in >> Partition >> MulticastAddress >> MulticastNetwork; + } + +private: + void initialize() + { + MulticastAddress = "224.200.100.100"; + MulticastNetwork = "10.149.0.0"; + +// <<BeginUserCode>> + +// <<EndUserCode>> + } + + +// <<BeginUserCode>> + +// <<EndUserCode>> +}; + +// <<BeginUserCode>> + +// <<EndUserCode>> +inline std::ostream & operator<<( std::ostream & out, const MultiCastGroupNamed & info ) { + info.print( out ); + return out; +} + +#endif // MULTICASTGROUPNAMED_H diff --git a/src/NameService.cxx b/src/NameService.cxx index b0763e1a8bdba457e804ab0b0c6e7a8735e0089a..a1c1b3e49d601295ba54a4c21edb72dc2f48b00e 100644 --- a/src/NameService.cxx +++ b/src/NameService.cxx @@ -3,10 +3,13 @@ #include "transport/Interface.h" #include "MsgInfo.h" +#include "MultiCastGroup.h" +#include "MultiCastGroupNamed.h" #include "is/infostream.h" #include "is/infodictionary.h" #include "is/serveriterator.h" +#include "is/infoiterator.h" #include <algorithm> @@ -346,5 +349,86 @@ namespace daq { return boost::asio::ip::address(); } + std::string NameService::allocate_multicast_address(const std::string& addr, const std::string& network) + { + MultiCastGroup group; + ISInfoDictionary dict(m_partition); + + if(addr == "*") { + + // Find potential entry in initial partition + ISInfoIterator it(IPCPartition(), "RunParams", MultiCastGroup::type()); + bool found = false; + + while(it++) { + it.value(group); + if(group.Partition == m_partition.name()) { + // found our partition. + found = true; + break; + } + } + + if(!found) { + // allocate a new group. + + unsigned short index = 1; + std::string name_prefix = "RunParams.MultiCast-"; + + group.Partition = m_partition.name(); + group.MulticastAddress = std::string("224.100.100.") + boost::lexical_cast<std::string>(index); + group.MulticastNetwork = network; + + while(!found && index < 256) { + + try { + dict.insert(name_prefix + group.MulticastAddress, group); + found = true; + } catch(...) { + // try next + index++; + } + } + } + + if(!found) { + // A dynamic address was requested, but we could not allocate one... + throw CannotAllocateMulticast(ERS_HERE); + } + } + + ISServerIterator servers(m_partition, m_is_server + ".*"); + if(servers.entries() == 0) { + throw InvalidISServer(ERS_HERE,m_is_server); + } + while(servers++) { + // may throw + try { + dict.checkin(std::string(servers.name()) + ".MultiCastAddress", group); + } catch(ers::Issue& reason) { + throw InvalidISServer(ERS_HERE, servers.name(), reason); + } + } + + return group.MulticastAddress; + } + + std::string NameService::lookup_multicast_address(const std::string& addr) const + { + if(addr == "*") { + + MultiCastGroupNamed group(m_partition, m_is_server + ".MultiCastAddress"); + + try { + group.checkout(); + return group.MulticastAddress; + + } catch (ers::Issue& ex) { + throw CannotResolve(ERS_HERE, addr, ex); + } + } + + return addr; + } } }