CHIRP#
Notes on Sockets#
CHIRP uses multicast for network discovery, meaning message are distributed to all
computers in a network which subscribed to the corresponding multicast group. A multicast group is just a specific multicast
IP address. CHIRP uses 239.192.7.123
as its multicast address and uses port 7123
.
To receive multicasts, a socket is required which binds to the multicast endpoint (which is the multicast address and port)
and joins the multicast group on each network interface. Since there might be multiple programs running CHIRP on one machine,
it is important to ensure that the port is not blocked by one program. To ensure that a socket can be used by more than one
program, the SO_REUSEADDR
socket option has to be enabled. To receive multicast messages from other programs running CHIRP
the IP_MULTICAST_LOOP
socket option has to be enabled.
For sending, a separate socket for each interface is required. Setting the interface is done by using the IP_MULTICAST_IF
option. Sending sockets also requires the SO_REUSEADDR
socket option. Note that the IP_MULTICAST_LOOP
option should not
be set since it is better to add the loopback interface explicitly to avoid message duplication when using multiple network
interfaces. Further it is not required to join the multicast group, sending can be achieved by sending a message to the
multicast endpoint.
Multicasts can also “hop” over network boundaries (i.e. routers) using the IP_MULTICAST_TTL
socket option (which defines
the number of network hops). By default CHIRP uses a TTL of eight. However, routers might still be configured to drop
multicast instead of forwarding them.
CHIRP Testing Tool#
To run the CHIRP testing tool, run:
./build/cxx/constellation/tools/chirp_manager CONSTELLATION_GROUP NAME INTERFACE
The following commands are available:
list_registered_services
: list of services registered by the user in the managerlist_discovered_services [SERVICE]
: list of services discovered by the manager and are in the same groupregister_service [SERVICE] [PORT]
: register a service in the managerregister_callback [SERVICE]
: register a discover callback for a service that prints the discovered servicerequest [SERVICE]
: send a CHIRP request for a given serviceunregister_service [SERVICE] [PORT]
: unregister a service in the managerunregister_callback [SERVICE]
: unregister a discover callback for a servicereset
: unregister all services and callbacks, and forget discovered servicesquit
constellation::chirp
Namespace#
-
enum class constellation::chirp::ServiceStatus : std::uint8_t#
Status of a service for callbacks from the
Manager
Values:
-
enumerator DISCOVERED#
The service is newly discovered
-
enumerator DEPARTED#
The service departed
-
enumerator DEAD#
The service is considered dead without departure
-
enumerator DISCOVERED#
-
using constellation::chirp::DiscoverCallback = void(DiscoveredService service, ServiceStatus status, std::any user_data)#
Function signature for user callback
The first argument (
service
) contains the discovered service, the second argument is an enum that indicates the status of the service, i.e. whether it is newly discovered, departing, or considered dead, and the third argument (user_data
) is arbitrary user data passed to the callback (done viaManager::RegisterDiscoverCallback
).It is recommended to pass the user data wrapped in an atomic
std::shared_ptr
since the callback is launched asynchronously in a detachedstd::thread
. If the data is modified, it is recommended to use atomic types when possible or astd::mutex
for locking to ensure thread-safe access.
-
struct DiscoverCallbackEntry#
- #include <constellation/core/chirp/Manager.hpp>
Entry for a user callback in the
Manager
for newly discovered or departing servicesPublic Functions
-
std::strong_ordering operator<=>(const DiscoverCallbackEntry &other) const#
Public Members
-
DiscoverCallback *callback#
Function pointer to a callback
-
protocol::CHIRP::ServiceIdentifier service_id#
Service identifier of the service for which callbacks should be received
-
std::any user_data#
Arbitrary user data passed to the callback function
For information on lifetime and thread-safety see
DiscoverCallback
.
-
std::strong_ordering operator<=>(const DiscoverCallbackEntry &other) const#
-
struct DiscoveredService#
- #include <constellation/core/chirp/Manager.hpp>
A service discovered by the
Manager
Public Functions
-
std::string to_uri() const#
Convert service information to a URI
-
std::strong_ordering operator<=>(const DiscoveredService &other) const#
-
std::string to_uri() const#
-
class Manager#
- #include <constellation/core/chirp/Manager.hpp>
Manager handling CHIRP messages
Public Functions
-
Manager(std::string_view group_name, std::string_view host_name, const std::vector<networking::Interface> &interfaces)#
- Parameters:
group_name – Group name of the group to join
host_name – Host name for outgoing messages
interfaces – Interfaces to use
-
virtual ~Manager()#
-
inline message::MD5Hash getGroupID() const#
- Returns:
Group ID (MD5Hash of the group name)
-
inline message::MD5Hash getHostID() const#
- Returns:
Host ID (MD5Hash of the host name)
-
void start()#
Start the background thread of the manager
-
bool registerService(protocol::CHIRP::ServiceIdentifier service_id, networking::Port port)#
Register a service offered by the host in the manager
Calling this function sends a CHIRP message with OFFER type, and registers the service such that the manager responds to CHIRP messages with REQUEST type and the corresponding service identifier.
- Parameters:
service_id – Service identifier of the offered service
port – Port of the offered service
- Return values:
true – if the service was registered
false – if the service was already registered
-
bool unregisterService(protocol::CHIRP::ServiceIdentifier service_id, networking::Port port)#
Unregister a previously registered service offered by the host in the manager
Calling this function sends a CHIRP message with DEPART type and removes the service from manager. See also
RegisterService
.- Parameters:
service_id – Service identifier of the previously offered service
port – Port of the previously offered service
- Return values:
true – If the service was unregistered
false – If the service was never registered
-
void unregisterServices()#
Unregisters all offered services registered in the manager
Equivalent to calling
UnregisterService
for every registered service.
-
std::set<RegisteredService> getRegisteredServices()#
Get the list of services currently registered in the manager
- Returns:
Set with all currently registered services
-
bool registerDiscoverCallback(DiscoverCallback *callback, protocol::CHIRP::ServiceIdentifier service_id, std::any user_data)#
Register a user callback for newly discovered or departing services
Note that a callback function can be registered multiple times for different services.
Warning
Discover callbacks block the execution of further processing of CHIRP requests and offers, callbacks that take a long time should offload the work to a new thread.
- Parameters:
callback – Function pointer to a callback
service_id – Service identifier of the service for which callbacks should be received
user_data – Arbitrary user data passed to the callback function (see
DiscoverCallback
)
- Return values:
true – If the callback/service/user_data combination was registered
false – If the callback/service/user_data combination was already registered
-
bool unregisterDiscoverCallback(DiscoverCallback *callback, protocol::CHIRP::ServiceIdentifier service_id)#
Unregister a previously registered callback for newly discovered or departing services
- Parameters:
callback – Function pointer to the callback of registered callback entry
service_id – Service identifier of registered callback entry
- Return values:
true – If the callback entry was unregistered
false – If the callback entry was never registered
-
void unregisterDiscoverCallbacks()#
Unregisters all discovery callbacks registered in the manager
Equivalent to calling
UnregisterDiscoverCallback
for every discovery callback.
-
void forgetDiscoveredService(protocol::CHIRP::ServiceIdentifier identifier, message::MD5Hash host_id)#
Forget the previously discovered services of the given type and host ID, if present.
- Parameters:
identifier – Identifier of the discovered service to be forgotten
host_id – Host ID of the discovered service to be forgotten
-
void forgetDiscoveredServices(message::MD5Hash host_id)#
Forget all previously discovered services of a given host.
- Parameters:
host_id – Host ID of the discovered services to be forgotten
-
void forgetDiscoveredServices()#
Forget all previously discovered services
-
std::vector<DiscoveredService> getDiscoveredServices()#
Returns list of all discovered services
- Returns:
Vector with all discovered services
-
std::vector<DiscoveredService> getDiscoveredServices(protocol::CHIRP::ServiceIdentifier service_id)#
Returns list of all discovered services with a given service identifier
- Parameters:
service_id – Service identifier for discovered services that should be listed
- Returns:
Vector with all discovered services with the given service identifier
-
void sendRequest(protocol::CHIRP::ServiceIdentifier service_id)#
Send a discovery request for a specific service identifier
This sends a CHIRP message with a REQUEST type and a given service identifier. Other hosts might reply with a CHIRP message with OFFER type for the given service identifier. These can be retrieved either by registering a user callback (see
RegisterDiscoverCallback
) or by getting the list of discovered services shortly after (seeGetDiscoveredServices
).- Parameters:
service_id – Service identifier to send a request for
-
Manager(std::string_view group_name, std::string_view host_name, const std::vector<networking::Interface> &interfaces)#
-
struct MulticastMessage#
- #include <constellation/core/chirp/MulticastSocket.hpp>
Incoming multicast message
-
class MulticastSocket#
- #include <constellation/core/chirp/MulticastSocket.hpp>
Multicast handler for multicast message
Public Functions
-
MulticastSocket(const std::vector<networking::Interface> &interfaces, const asio::ip::address_v4 &multicast_address, asio::ip::port_type multicast_port)#
Construct multicast handler
- Parameters:
interfaces – List of interfaces for outgoing messages
multicast_address – Multicast address
multicast_port – Multicast port
-
void sendMessage(std::span<const std::byte> message)#
Send multicast message to all interfaces
- Parameters:
message – Message in bytes
-
std::optional<MulticastMessage> recvMessage(std::chrono::steady_clock::duration timeout)#
Receive multicast message within a timeout
- Parameters:
timeout – Duration for which to block function call
- Returns:
Multicast message if received
-
MulticastSocket(const std::vector<networking::Interface> &interfaces, const asio::ip::address_v4 &multicast_address, asio::ip::port_type multicast_port)#
-
struct RegisteredService#
- #include <constellation/core/chirp/Manager.hpp>
A service offered by the host and announced by the
Manager
Public Functions
-
std::strong_ordering operator<=>(const RegisteredService &other) const#
-
std::strong_ordering operator<=>(const RegisteredService &other) const#