// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0 #ifndef EID_H_INCLUDED #define EID_H_INCLUDED #include #include #include #include /** * The maximum supported length for EID strings. */ #define EID_MAX_LEN (INT16_MAX - 1) #ifndef EID_IPN_FORCE_2_ELEMENT /** * Enforce using the 2-element format for ipn EIDs in outgoing BPv7 bundles and internal strings. */ #define EID_IPN_FORCE_2_ELEMENT 0 #endif // EID_IPN_FORCE_2_ELEMENT /** * The URI scheme used for an EID. * See: https://www.rfc-editor.org/rfc/rfc9171.html#section-9.6 */ enum eid_scheme { // Used when the scheme could not be detected or when errors occur, e.g., due to invalid // function arguments. A struct eid with this scheme is considered an "error value". EID_SCHEME_UNKNOWN = -1, EID_SCHEME_DTN = 1, EID_SCHEME_IPN = 2, }; /** * An EID conforming to the `ipn` scheme. */ struct ipn_eid { // NOTE that this is the FQNN (fully qualified node number). To access the allocator ID or // the assigned node number, use ipn_eid_allocator() and ipn_eid_node(). uint64_t fully_qualified_node_number; uint64_t service_number; }; /** * The internal representation for an endpoint identifier. When in this struct representation, EIDs * can always be considered valid, except if the scheme value marks an instance as invalid, * which can be checked using `eid_is_error()`. */ struct eid { enum eid_scheme scheme; // Note: We may consider adding a flags field here, to specify how to represent the EID in // an outgoing bundle, if any inbound conversion makes things ambigous. // enum eid_original_representation_flags original_representation_flags; union { struct ipn_eid ipn_eid; // If the EID uses the `dtn` scheme, this is the full EID, including scheme "dtn:". // Note that we consider a missing trailing slash in `dtn`-scheme EIDs as valid. char *dtn_eid; }; }; /** * Checks if the provided EID indicates an error (or invalid value). * * @param eid the EID structure to be checked * * @return true, if the EID structure indicates an error (or invalid value); false otherwise */ static inline bool eid_is_error(const struct eid eid) { return (int)eid.scheme < 0; } /** * Returns an invalid `struct eid` instance (an error value). * * @return an invalid `struct eid` that can represent an error value */ static inline struct eid eid_get_invalid(void) { return (struct eid){ .scheme = EID_SCHEME_UNKNOWN }; } /** * Returns a `struct eid` instance representing the Null Endpoint ("dtn:none"). * * @return a `struct eid` instance representing the Null Endpoint ("dtn:none") */ static inline struct eid eid_get_null(void) { return (struct eid){ .scheme = EID_SCHEME_DTN, .dtn_eid = NULL }; } /** * Checks if the provided EID is the Null Endpoint. * * @param eid the EID structure to be checked * * @return true, if the EID is valid and represents the Null Endpoint; false otherwise */ static inline bool eid_is_null(const struct eid eid) { if (eid.scheme == EID_SCHEME_DTN) return eid.dtn_eid == NULL; else if (eid.scheme == EID_SCHEME_IPN) // RFC9758 3.4.1: processors of such ipn URIs MUST consider them as the Null ipn URI return eid.ipn_eid.fully_qualified_node_number == 0; else return false; } /** * Checks if the provided EID is a LocalNode endpoint. * * @param eid the EID structure to be checked * * @return true, if the EID is valid and represents a LocalNode endpoint; false otherwise * @note currently, LocalNode EIDs are only supported by the `ipn` scheme (RFC9758) */ static inline bool eid_is_localnode(const struct eid eid) { if (eid.scheme == EID_SCHEME_DTN) return false; else if (eid.scheme == EID_SCHEME_IPN) // RFC9758 3.4.2 return eid.ipn_eid.fully_qualified_node_number == 0x00000000FFFFFFFFULL; else return false; } /** * Checks if the provided EID is a private-use endpoint. * * @param eid the EID structure to be checked * * @return true, if the EID is valid and represents a private-use endpoint; false otherwise * @note currently, private-use EIDs are only supported by the `ipn` scheme (RFC9758) */ static inline bool eid_is_private_use(const struct eid eid) { if (eid.scheme == EID_SCHEME_DTN) return false; else if (eid.scheme == EID_SCHEME_IPN) // RFC9758 3.4.3, RFC9758 9.1 return ( eid.ipn_eid.fully_qualified_node_number >= 0x0000000000000001ULL && eid.ipn_eid.fully_qualified_node_number <= 0x0000000000003FFFULL ); else return false; } /** * Obtains the ipn allocator identifier for the provided struct ipn_eid. * * @param ipn_eid the ipn EID * * @return the allocator identifier */ static inline uint32_t ipn_eid_allocator(struct ipn_eid ipn_eid) { return ipn_eid.fully_qualified_node_number >> 32; } /** * Obtains the ipn assigned node number for the provided struct ipn_eid. * * @param ipn_eid the ipn EID * * @return the assigned node number */ static inline uint32_t ipn_eid_node(struct ipn_eid ipn_eid) { return ipn_eid.fully_qualified_node_number & 0x00000000FFFFFFFFULL; } /** * Obtains the 64-bit fully qualified node number (FQNN) for the provided allocator and node. * * @param allocator_id the allocator identifier * @param node_number the node number * * @return the fully qualified node number, as it is part of struct ipn_eid */ static inline uint64_t ipn_eid_get_fqnn(const uint32_t allocator_id, const uint32_t node_number) { return ((uint64_t)allocator_id << 32) | (uint64_t)node_number; } /** * Validates, normalizes, and converts the given EID string representation to a `struct eid`. * * @param eid_str EID string * * @return A `struct eid` instance, potentially normalized. Must be freed using eid_free(). * On error, an invalid `struct eid` is returned (check using `eid_is_error`). */ struct eid eid_from_string(const char *eid_str); /** * Converts the given EID structure to its URI string representation. * * @param eid EID structure to be converted * * @return A heap-allocated C string representing the EID, or NULL on error. */ char *eid_to_string(const struct eid eid); /** * Converts the given EID structure to its URI string representation, allowing to force using the * 2-element ipn EID format (e.g. for outgoing RFC 5050 bundles). * * @param eid EID structure to be converted * @param force_ipn_2_element if eid is an ipn-scheme EID, enforce the 2-element representation * * @return A heap-allocated C string representing the EID, or NULL on error. */ char *eid_to_string2(const struct eid eid, bool force_ipn_2_element); /** * Releases resources associated with the provided EID structure. * * @param eid the EID data structure to be released */ void eid_free(struct eid eid); /** * Duplicates (clones) the given EID structure. * * @param eid EID structure to be duplicated * * @return Another EID structure representing the same EID value as the provided one. * On error, an invalid `struct eid` is returned (check using `eid_is_error`). */ struct eid eid_dup(const struct eid eid); /** * Checks if two EIDs have an equal value. * * @param eid1 First EID to be compared * @param eid1 Second EID to be compared * * @return true, if both EID structures are valid and have the same value. */ bool eid_eq(const struct eid eid1, const struct eid eid2); /** * Checks if two EIDs belong to the same node. * * @param eid1 First EID to be compared * @param eid1 Second EID to be compared * * @return true, if both EID structures are valid and represent endpoints on the same node. */ bool eid_node_eq(const struct eid eid1, const struct eid eid2); /** * Get the administrative-endpoint node ID for a given EID. * * @param eid the EID * * @return For ipn EIDs, this returns "ipn:N.0" whereas "N" is the node number. * For dtn EIDs, "dtn://node/" is returned, whereas "node" is the node name. * On error, an invalid `struct eid` is returned (check using `eid_is_error`). */ struct eid eid_get_admin_endpoint(const struct eid eid); /** * Get the full EID for an agent registered at the given node. * * @param node_id a node ID for the node where the agent is registered * @param agent_id string representation of an agent ID that is valid for the scheme of the node ID * * @return For ipn EIDs, this returns "ipn:N.A" whereas "N" is the node number and A the agent ID. * For dtn EIDs, "dtn://node/agent" is returned, whereas "node" is the node name and * "agent" is the agent ID. On error, an invalid `struct eid` is returned (check using * `eid_is_error`). */ struct eid eid_get_agent_eid(const struct eid node_id, const char *agent_id); /** * Obtain the agent ID string for a given EID. * * @param eid EID to get the agent from * * @return The agent ID string, heap-allocated. NULL on error. * @note For the Null Endpoint, there is no agent ID, so this function returns NULL. */ char *eid_get_agent_id_str(const struct eid eid); /** * Validate the given EID string. * * @param eid_str EID string * * @return true if the EID string is valid. */ bool eidstr_is_valid(const char *const eid_str); /** * Validate the given dtn-scheme EID string. * * @param eid_str EID string using the `dtn` scheme * * @return true if the EID string is valid. * @note We consider a missing trailing slash in `dtn`-scheme EIDs as valid. */ bool eidstr_dtn_is_valid(const char *const eid_str); /** * Validate the demux part of a dtn EID, i.e., the agent ID for us. * * @param demux_str demux string (null-terminated) * * @return true if the demux string is valid. */ bool eidstr_dtn_demux_is_valid(const char *demux_str); /** * Determine the EID scheme for the given EID string. * * @param eid_str EID string * * @return The EID scheme; EID_SCHEME_UNKNOWN if no scheme can be determined. */ enum eid_scheme eidstr_get_eid_scheme(const char *eid_str); /** * Parse (and validate) the unsigned int64 contained in an ipn EID. * * @param cur String starting with the number to be parsed * @param out An optional pointer to return the parsed number * * @return A pointer to the first character after the number or NULL on failure. */ const char *eidstr_parse_ipn_ull(const char *const cur, uint64_t *const out); /** * Validate the given ipn-scheme EID string. * * @param eid_str EID string * @param fqnn_out An optional pointer to return the fully qualified node number * @param service_out An optional pointer to return the service number * * @return true if the EID string is a valid ipn EID. * @note There is a special case for ipn EIDs: if the node number is zero but the service number is * nonzero, we treat this as valid and return a service number of zero, to enforce * normalization when using this function to create an EID structure for such endpoints. */ bool eidstr_ipn_is_valid( const char *const eid_str, uint64_t *const fqnn_out, uint64_t *const service_out); #endif // EID_H_INCLUDED