mirror of
https://gitlab.com/d3tn/ud3tn.git
synced 2026-08-13 12:33:27 +02:00
Removes unused includes detected by the clangd LSP. Signed-off-by: Maximilian Nitsch <maximilian.nitsch@d3tn.com>
414 lines
9.8 KiB
C
414 lines
9.8 KiB
C
// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
|
|
#include "bundle7/bundle7.h"
|
|
#include "bundle7/eid.h"
|
|
|
|
#include "ud3tn/bundle.h"
|
|
#include "ud3tn/eid.h"
|
|
|
|
#include "cbor.h"
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
// --------------------------------
|
|
// Endpoint Identifier (EID) Parser
|
|
// --------------------------------
|
|
|
|
|
|
static CborError eid_parse_dtn(CborValue *it, char **eid);
|
|
static CborError eid_parse_ipn(CborValue *it, struct ipn_eid *eid);
|
|
|
|
|
|
CborError bundle7_eid_parse_cbor(CborValue *it, struct eid *eid)
|
|
{
|
|
CborValue recursed;
|
|
CborError err;
|
|
size_t length;
|
|
uint64_t schema;
|
|
|
|
if (!cbor_value_is_array(it) || !cbor_value_is_length_known(it))
|
|
return CborErrorIllegalType;
|
|
|
|
// Array must contain 2 items
|
|
if (cbor_value_get_array_length(it, &length) != CborNoError)
|
|
return CborErrorIllegalType;
|
|
if (length != 2)
|
|
return CborErrorIllegalType;
|
|
|
|
// Enter EID array
|
|
err = cbor_value_enter_container(it, &recursed);
|
|
if (err)
|
|
return err;
|
|
|
|
// EID schema (first element)
|
|
if (!cbor_value_is_unsigned_integer(&recursed))
|
|
return CborErrorIllegalType;
|
|
|
|
cbor_value_get_uint64(&recursed, &schema);
|
|
|
|
// Second item (schema specific)
|
|
err = cbor_value_advance_fixed(&recursed);
|
|
if (err)
|
|
return err;
|
|
|
|
char *dtn_eid;
|
|
struct ipn_eid ipn_eid;
|
|
|
|
// Call schema specific parsing functions
|
|
switch (schema) {
|
|
case BUNDLE_V7_EID_SCHEMA_DTN:
|
|
err = eid_parse_dtn(&recursed, &dtn_eid);
|
|
break;
|
|
case BUNDLE_V7_EID_SCHEMA_IPN:
|
|
err = eid_parse_ipn(&recursed, &ipn_eid);
|
|
break;
|
|
// unknown schema
|
|
default:
|
|
return CborErrorIllegalType;
|
|
}
|
|
|
|
// SSP parsing returned error
|
|
if (err)
|
|
return err;
|
|
|
|
assert(cbor_value_at_end(&recursed));
|
|
|
|
// Leave EID array
|
|
err = cbor_value_leave_container(it, &recursed);
|
|
// Validation/post-processing
|
|
if (schema == BUNDLE_V7_EID_SCHEMA_DTN) {
|
|
if (err) {
|
|
free(dtn_eid);
|
|
return err;
|
|
} else if (dtn_eid != NULL && !eidstr_dtn_is_valid(dtn_eid)) {
|
|
free(dtn_eid);
|
|
return CborErrorImproperValue;
|
|
}
|
|
eid->scheme = EID_SCHEME_DTN;
|
|
eid->dtn_eid = dtn_eid;
|
|
return CborNoError;
|
|
}
|
|
if (err)
|
|
return err;
|
|
// NOTE: We could consider normalizing ipn:0.0 or ipn:0.x to dtn:none here.
|
|
// We do not do this (for now) to ensure that the primary block stays unchanged.
|
|
// This explicitly includes the case where an ipn EID has a zero node number but nonzero
|
|
// service number, which is considered equal to the Null Endpoint.
|
|
eid->scheme = EID_SCHEME_IPN;
|
|
eid->ipn_eid = ipn_eid;
|
|
return CborNoError;
|
|
}
|
|
|
|
|
|
CborError eid_parse_dtn(CborValue *it, char **eid)
|
|
{
|
|
CborError err;
|
|
size_t length;
|
|
uint64_t num;
|
|
|
|
// Special case:
|
|
//
|
|
// null-EID ("dtn:none")
|
|
//
|
|
if (cbor_value_is_unsigned_integer(it)) {
|
|
cbor_value_get_uint64(it, &num);
|
|
|
|
// The only allowed value here is zero
|
|
if (num != 0)
|
|
return CborErrorIllegalType;
|
|
|
|
// Go to end of array
|
|
cbor_value_advance_fixed(it);
|
|
|
|
// Allocate output buffer
|
|
*eid = NULL;
|
|
return CborNoError;
|
|
}
|
|
|
|
// The SSP of the "dtn" schema is a CBOR text string
|
|
if (!cbor_value_is_text_string(it))
|
|
return CborErrorIllegalType;
|
|
|
|
// Determine SSP length. We do not check if the length is known because
|
|
// this is already done in cbor_value_get_string_length(). If the
|
|
// length is unknown a CborErrorUnknownLength will be returned
|
|
err = cbor_value_get_string_length(it, &length);
|
|
if (err)
|
|
return err;
|
|
|
|
// Remaining bytes are not sufficient
|
|
if ((size_t)(it->parser->source.end - it->source.ptr) < length)
|
|
return CborErrorUnexpectedEOF;
|
|
|
|
// The number of bytes written to the buffer will be written to the
|
|
// length variable
|
|
length += 1; // '\0' termination
|
|
|
|
// Allocate output buffer for "dtn:" prefix + SSP
|
|
*eid = malloc(4 + length);
|
|
if (*eid == NULL)
|
|
return CborErrorOutOfMemory;
|
|
|
|
// Copy prefix
|
|
memcpy(*eid, "dtn:", 4);
|
|
|
|
// Copy SSP + '\0' and advance iterator to next element after SSP.
|
|
err = cbor_value_copy_text_string(it, *eid + 4, &length, it);
|
|
if (err) {
|
|
free(*eid);
|
|
// Ensure that the pointer is not used afterwards.
|
|
// Otherwise a parser reset might try to double-free it.
|
|
*eid = NULL;
|
|
return err;
|
|
}
|
|
|
|
return CborNoError;
|
|
}
|
|
|
|
|
|
static CborError eid_parse_ipn(CborValue *it, struct ipn_eid *eid)
|
|
{
|
|
CborValue recursed;
|
|
CborError err;
|
|
uint64_t nodenum, servicenum;
|
|
uint64_t allocatorid_tmp;
|
|
size_t array_length;
|
|
|
|
// Enter array
|
|
if (!cbor_value_is_array(it) || !cbor_value_is_length_known(it))
|
|
return CborErrorIllegalType;
|
|
|
|
// Get array length to determine EID format
|
|
if (cbor_value_get_array_length(it, &array_length) != CborNoError)
|
|
return CborErrorIllegalType;
|
|
|
|
err = cbor_value_enter_container(it, &recursed);
|
|
if (err)
|
|
return err;
|
|
|
|
if (array_length == 2) {
|
|
// FQNN
|
|
if (!cbor_value_is_unsigned_integer(&recursed))
|
|
return CborErrorIllegalType;
|
|
cbor_value_get_uint64(&recursed, &nodenum);
|
|
} else if (array_length == 3) {
|
|
// Allocator ID
|
|
if (!cbor_value_is_unsigned_integer(&recursed))
|
|
return CborErrorIllegalType;
|
|
cbor_value_get_uint64(&recursed, &allocatorid_tmp);
|
|
// Advance to node number
|
|
err = cbor_value_advance_fixed(&recursed);
|
|
if (err)
|
|
return err;
|
|
// Assigned node number
|
|
if (!cbor_value_is_unsigned_integer(&recursed))
|
|
return CborErrorIllegalType;
|
|
cbor_value_get_uint64(&recursed, &nodenum);
|
|
if (allocatorid_tmp > UINT32_MAX || nodenum > UINT32_MAX)
|
|
return CborErrorIllegalType;
|
|
nodenum = ipn_eid_get_fqnn(allocatorid_tmp, nodenum);
|
|
} else {
|
|
// Invalid array length
|
|
return CborErrorIllegalType;
|
|
}
|
|
|
|
// Advance to service number
|
|
err = cbor_value_advance_fixed(&recursed);
|
|
if (err)
|
|
return err;
|
|
|
|
// Service number
|
|
// --------------
|
|
if (!cbor_value_is_unsigned_integer(&recursed))
|
|
return CborErrorIllegalType;
|
|
|
|
cbor_value_get_uint64(&recursed, &servicenum);
|
|
|
|
err = cbor_value_advance_fixed(&recursed);
|
|
if (err)
|
|
return err;
|
|
|
|
// Expect end of array
|
|
if (!cbor_value_at_end(&recursed))
|
|
return CborErrorIllegalType;
|
|
|
|
|
|
// Leave array
|
|
err = cbor_value_leave_container(it, &recursed);
|
|
if (err)
|
|
return err;
|
|
|
|
eid->fully_qualified_node_number = nodenum;
|
|
eid->service_number = servicenum;
|
|
|
|
return CborNoError;
|
|
}
|
|
|
|
|
|
|
|
struct eid bundle7_eid_parse(const uint8_t *buffer, size_t length)
|
|
{
|
|
struct eid eid;
|
|
CborValue it;
|
|
CborParser parser;
|
|
CborError err;
|
|
|
|
err = cbor_parser_init(buffer, length, 0, &parser, &it);
|
|
if (err != CborNoError)
|
|
return eid_get_invalid();
|
|
|
|
err = bundle7_eid_parse_cbor(&it, &eid);
|
|
if (err != CborNoError)
|
|
return eid_get_invalid();
|
|
|
|
return eid;
|
|
}
|
|
|
|
|
|
// ------------------------------------
|
|
// Endpoint Identifier (EID) Serializer
|
|
// ------------------------------------
|
|
|
|
//static const uint8_t _dtn_none[3] = {
|
|
// 0x82, 0x01, 0x00
|
|
//};
|
|
|
|
CborError serialize_dtn_none(CborEncoder *encoder)
|
|
{
|
|
CborEncoder recursed;
|
|
|
|
cbor_encoder_create_array(encoder, &recursed, 2);
|
|
cbor_encode_uint(&recursed, BUNDLE_V7_EID_SCHEMA_DTN);
|
|
cbor_encode_uint(&recursed, 0);
|
|
cbor_encoder_close_container(encoder, &recursed);
|
|
|
|
return CborNoError;
|
|
}
|
|
|
|
|
|
CborError serialize_dtn(const char *eid, CborEncoder *encoder)
|
|
{
|
|
CborEncoder recursed;
|
|
size_t ssp_length = strlen(eid) - 4;
|
|
|
|
// EID container
|
|
cbor_encoder_create_array(encoder, &recursed, 2);
|
|
|
|
// Schema
|
|
cbor_encode_uint(&recursed, BUNDLE_V7_EID_SCHEMA_DTN);
|
|
|
|
// SSP
|
|
cbor_encode_text_string(&recursed, eid + 4, ssp_length);
|
|
|
|
// EID container
|
|
cbor_encoder_close_container(encoder, &recursed);
|
|
|
|
return CborNoError;
|
|
}
|
|
|
|
|
|
CborError serialize_ipn(const struct ipn_eid eid, CborEncoder *encoder)
|
|
{
|
|
CborEncoder inner, ssp;
|
|
|
|
// EID container
|
|
cbor_encoder_create_array(encoder, &inner, 2);
|
|
|
|
// Schema
|
|
cbor_encode_uint(&inner, BUNDLE_V7_EID_SCHEMA_IPN);
|
|
|
|
// SSP
|
|
if (ipn_eid_allocator(eid) == 0 || EID_IPN_FORCE_2_ELEMENT) {
|
|
cbor_encoder_create_array(&inner, &ssp, 2);
|
|
cbor_encode_uint(&ssp, eid.fully_qualified_node_number);
|
|
cbor_encode_uint(&ssp, eid.service_number);
|
|
cbor_encoder_close_container(&inner, &ssp);
|
|
} else {
|
|
cbor_encoder_create_array(&inner, &ssp, 3);
|
|
cbor_encode_uint(&ssp, ipn_eid_allocator(eid));
|
|
cbor_encode_uint(&ssp, ipn_eid_node(eid));
|
|
cbor_encode_uint(&ssp, eid.service_number);
|
|
cbor_encoder_close_container(&inner, &ssp);
|
|
}
|
|
|
|
// EID container
|
|
cbor_encoder_close_container(encoder, &inner);
|
|
|
|
return CborNoError;
|
|
}
|
|
|
|
|
|
uint8_t *bundle7_eid_serialize_alloc(const struct eid eid, size_t *length)
|
|
{
|
|
const size_t buffer_size = bundle7_eid_sizeof(eid);
|
|
|
|
if (buffer_size == 0)
|
|
return NULL;
|
|
|
|
uint8_t *const buffer = malloc(buffer_size);
|
|
|
|
// We could not allocate enough memory
|
|
if (buffer == NULL)
|
|
return NULL;
|
|
|
|
int written = bundle7_eid_serialize(eid, buffer, buffer_size);
|
|
|
|
if (written <= 0) {
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
// Shorten buffer to correct length
|
|
uint8_t *compress = realloc(buffer, written);
|
|
|
|
// Something went south during realloc, clear buffer and abort
|
|
if (compress == NULL) {
|
|
// False positive in some versions of cppcheck. It is correct
|
|
// to free here as `realloc` failed and does not free.
|
|
// cppcheck-suppress doubleFree
|
|
free(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
*length = (size_t)written;
|
|
return compress;
|
|
}
|
|
|
|
CborError bundle7_eid_serialize_cbor(const struct eid eid, CborEncoder *encoder)
|
|
{
|
|
// Special case: null-EID
|
|
if (eid.scheme == EID_SCHEME_DTN && eid.dtn_eid == NULL)
|
|
return serialize_dtn_none(encoder);
|
|
// DTN (allows empty SSPs)
|
|
else if (eid.scheme == EID_SCHEME_DTN)
|
|
return serialize_dtn(eid.dtn_eid, encoder);
|
|
// IPN
|
|
else if (eid.scheme == EID_SCHEME_IPN)
|
|
return serialize_ipn(eid.ipn_eid, encoder);
|
|
// Unknown schema
|
|
else
|
|
return CborErrorIllegalType;
|
|
}
|
|
|
|
int bundle7_eid_serialize(const struct eid eid, uint8_t *buffer, size_t buffer_size)
|
|
{
|
|
CborEncoder encoder;
|
|
CborError err;
|
|
|
|
cbor_encoder_init(&encoder, buffer, buffer_size, 0);
|
|
err = bundle7_eid_serialize_cbor(eid, &encoder);
|
|
|
|
// A non-recoverable error occurred
|
|
if (err != CborNoError && err != CborErrorOutOfMemory)
|
|
return -1;
|
|
|
|
// Out of memory (buffer too small)
|
|
if (cbor_encoder_get_extra_bytes_needed(&encoder) > 0)
|
|
return 0;
|
|
|
|
return cbor_encoder_get_buffer_size(&encoder, buffer);
|
|
}
|