ud3tn/test/unit/test_bundle6ParserSerializer.c
Felix Walter 973f35d132 Implement status report support in AAP 2.0
This enables AAP 2.0 clients to receive status reports with a new ADU
flag (as we already deliver BIBE bundles). Moreover, it allows clients
to set a report-to EID and sets all of the status report flags on newly
created bundles in case a report-to EID is provided.

Closes: #241

Signed-off-by: Felix Walter <felix.walter@d3tn.com>
2025-06-05 17:13:17 +02:00

335 lines
8.2 KiB
C

// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
#include "bundle6/create.h"
#include "bundle6/serializer.h"
#include "bundle6/parser.h"
#include "ud3tn/bundle.h"
#include "ud3tn/result.h"
#include "platform/hal_time.h"
#include "testud3tn_unity.h"
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
static const char test_payload[] = "PAYLOAD";
static struct bundle *b;
static bool verify_ok;
TEST_GROUP(bundle6ParserSerializer);
TEST_SETUP(bundle6ParserSerializer)
{
char *payload = malloc(sizeof(test_payload));
uint64_t creation_timestamp_s = 658489863; // 2020-11-12T09:51:03+00:00
memcpy(payload, test_payload, sizeof(test_payload));
b = bundle6_create_local(
payload,
sizeof(test_payload),
"dtn:sourceeid",
"dtn:desteid",
NULL,
creation_timestamp_s * 1000, 1, 42 * 1000,
BUNDLE_FLAG_REPORT_DELIVERY |
BUNDLE_V6_FLAG_CUSTODY_TRANSFER_REQUESTED
);
b->report_to = strdup("dtn:reportto");
b->current_custodian = strdup("dtn:custodian");
struct bundle_block *block = bundle_block_create(
BUNDLE_BLOCK_TYPE_HOP_COUNT
);
block->length = 1;
block->data = malloc(1);
block->flags = (
BUNDLE_V6_BLOCK_FLAG_HAS_EID_REF_FIELD |
BUNDLE_BLOCK_FLAG_MUST_BE_REPLICATED |
BUNDLE_V6_BLOCK_FLAG_LAST_BLOCK
);
struct endpoint_list *eid_list = malloc(sizeof(struct endpoint_list));
eid_list->eid = strdup("dtn:eidref1");
eid_list->next = NULL;
block->eid_refs = eid_list;
b->blocks->next = bundle_block_entry_create(block);
b->payload_block->flags = BUNDLE_BLOCK_FLAG_NONE;
}
TEST_TEAR_DOWN(bundle6ParserSerializer)
{
bundle_free(b);
}
static void verify_bundle(struct bundle *b)
{
TEST_ASSERT_NOT_NULL(b);
// Check header
TEST_ASSERT_EQUAL(6, b->protocol_version);
TEST_ASSERT_EQUAL(
BUNDLE_V6_FLAG_SINGLETON_ENDPOINT |
BUNDLE_FLAG_REPORT_DELIVERY |
BUNDLE_V6_FLAG_CUSTODY_TRANSFER_REQUESTED,
b->proc_flags
);
TEST_ASSERT_EQUAL(1, b->sequence_number);
TEST_ASSERT_EQUAL(658489863000, b->creation_timestamp_ms);
TEST_ASSERT_EQUAL(42000, b->lifetime_ms);
TEST_ASSERT_NOT_EQUAL(0, b->primary_block_length);
TEST_ASSERT_NOT_NULL(b->source);
TEST_ASSERT_EQUAL_STRING("dtn:sourceeid", b->source);
TEST_ASSERT_NOT_NULL(b->destination);
TEST_ASSERT_EQUAL_STRING("dtn:desteid", b->destination);
TEST_ASSERT_NOT_NULL(b->report_to);
TEST_ASSERT_EQUAL_STRING("dtn:reportto", b->report_to);
TEST_ASSERT_NOT_NULL(b->current_custodian);
TEST_ASSERT_EQUAL_STRING("dtn:custodian", b->current_custodian);
// Check blocks
TEST_ASSERT_NOT_NULL(b->blocks);
TEST_ASSERT_NOT_NULL(b->blocks->data);
TEST_ASSERT_NOT_NULL(b->blocks->next);
TEST_ASSERT_NOT_NULL(b->blocks->next->data);
TEST_ASSERT_NULL(b->blocks->next->next);
TEST_ASSERT_NOT_NULL(b->payload_block);
TEST_ASSERT_EQUAL_PTR(b->payload_block, b->blocks->data);
// Check payload block
TEST_ASSERT_EQUAL(
BUNDLE_BLOCK_FLAG_NONE,
b->payload_block->flags
);
TEST_ASSERT_EQUAL(
sizeof(test_payload),
b->payload_block->length
);
TEST_ASSERT_EQUAL_UINT8_ARRAY(
test_payload,
b->payload_block->data,
sizeof(test_payload)
);
// Check next block with EID refs
TEST_ASSERT_EQUAL(
BUNDLE_V6_BLOCK_FLAG_HAS_EID_REF_FIELD |
BUNDLE_BLOCK_FLAG_MUST_BE_REPLICATED |
BUNDLE_V6_BLOCK_FLAG_LAST_BLOCK,
b->blocks->next->data->flags
);
TEST_ASSERT_EQUAL(1, b->blocks->next->data->length);
TEST_ASSERT_NOT_NULL(b->blocks->next->data->eid_refs);
TEST_ASSERT_NOT_NULL(b->blocks->next->data->eid_refs->eid);
TEST_ASSERT_NULL(b->blocks->next->data->eid_refs->next);
TEST_ASSERT_EQUAL_STRING(
"dtn:eidref1",
b->blocks->next->data->eid_refs->eid
);
verify_ok = true;
}
static void verify_and_free_bundle(struct bundle *b, void *param)
{
(void)param;
verify_bundle(b);
bundle_free(b);
}
struct buf_info {
uint8_t *buf;
size_t pos;
};
static enum ud3tn_result _write(void *buf_info, const void *data,
const size_t len)
{
struct buf_info *bi = buf_info;
memcpy(&bi->buf[bi->pos], data, len);
bi->pos += len;
return UD3TN_OK;
}
TEST(bundle6ParserSerializer, parse_and_serialize)
{
verify_bundle(b);
TEST_ASSERT_TRUE(verify_ok);
const size_t serialized_size_before = bundle_get_serialized_size(b);
uint8_t *serializebuffer = malloc(serialized_size_before);
struct buf_info bi = {
.buf = serializebuffer,
.pos = 0,
};
TEST_ASSERT_NOT_NULL(serializebuffer);
TEST_ASSERT_NOT_EQUAL(0, serialized_size_before);
TEST_ASSERT_EQUAL(UD3TN_OK, bundle6_serialize(b, _write, &bi));
const size_t serialized_size_after = bi.pos;
TEST_ASSERT_EQUAL(serialized_size_before, serialized_size_after);
struct bundle6_parser p;
bundle6_parser_init(&p, verify_and_free_bundle, NULL);
verify_ok = false;
bundle6_parser_read(&p, serializebuffer, serialized_size_after);
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, p.basedata->status);
TEST_ASSERT_TRUE(verify_ok);
bundle6_parser_reset(&p);
TEST_ASSERT_EQUAL(PARSER_STATUS_GOOD, p.basedata->status);
free(serializebuffer);
}
// Bundle sourced and captured from ION v3.7.4, see #7 for details
static uint8_t ION_TEST_BUNDLE_IPN_CBHE[] = {
// Primary Block
// Version
0x06,
// Processing Flags
0x81, 0x14,
// Length
0x11,
// Destination: ipn:3.1 (CBHE)
0x03, 0x01,
// Source: dtn:none (CBHE)
0x00, 0x00,
// Report-to: dtn:none (CBHE)
0x00, 0x00,
// Custodian: dtn:none (CBHE)
0x00, 0x00,
// Timestamp
0x82, 0xDC, 0xAE, 0xC7, 0x2A,
// Seqnum
0x01,
// Lifetime
0x82, 0x2C,
// Dict. Length
0x00,
// 2nd Block (type 5)
0x05,
// Flags: discard if unproc
0x10,
// Length: 8 bytes
0x08,
// Data
0x69, 0x70, 0x6E, 0x00, 0x31, 0x2E, 0x30, 0x00,
// 3rd block (type 20)
0x14,
// Flags: replicate in every fragment
0x01,
// Length: 1 byte
0x01,
// Data
0x00,
// Payload Block (type 1)
0x01,
// Flags: "last block", "must be replicated"
0x09,
// Length: 10 bytes
0x0A,
// "hallo welt"
0x68, 0x61, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x65, 0x6C, 0x74
};
static void verify_and_free_ipn_cbhe_bundle(struct bundle *b, void *param)
{
(void)param;
TEST_ASSERT_NOT_NULL(b);
TEST_ASSERT_NOT_NULL(b->payload_block);
TEST_ASSERT_NOT_NULL(b->blocks);
TEST_ASSERT_NOT_NULL(b->blocks->data);
TEST_ASSERT_NOT_NULL(b->blocks->next);
TEST_ASSERT_NOT_NULL(b->blocks->next->data);
TEST_ASSERT_NOT_NULL(b->blocks->next->next);
TEST_ASSERT_NOT_NULL(b->blocks->next->next->data);
TEST_ASSERT_NULL(b->blocks->next->next->next);
TEST_ASSERT_EQUAL(6, b->protocol_version);
TEST_ASSERT_EQUAL(
BUNDLE_V6_FLAG_SINGLETON_ENDPOINT |
BUNDLE_FLAG_MUST_NOT_BE_FRAGMENTED |
BUNDLE_V6_FLAG_NORMAL_PRIORITY,
b->proc_flags
);
TEST_ASSERT_EQUAL(1, b->sequence_number);
TEST_ASSERT_EQUAL(300000, b->lifetime_ms);
TEST_ASSERT_NOT_EQUAL(10, b->primary_block_length);
TEST_ASSERT_EQUAL_STRING("ipn:3.1", b->destination);
TEST_ASSERT_EQUAL_STRING("dtn:none", b->source);
TEST_ASSERT_EQUAL_STRING("dtn:none", b->report_to);
TEST_ASSERT_EQUAL_STRING("dtn:none", b->current_custodian);
TEST_ASSERT_EQUAL_PTR(b->payload_block, b->blocks->next->next->data);
TEST_ASSERT_EQUAL(BUNDLE_BLOCK_TYPE_PAYLOAD, b->payload_block->type);
TEST_ASSERT_EQUAL(
BUNDLE_BLOCK_FLAG_MUST_BE_REPLICATED |
BUNDLE_V6_BLOCK_FLAG_LAST_BLOCK,
b->payload_block->flags
);
TEST_ASSERT_EQUAL_UINT8_ARRAY("hallo welt", b->payload_block->data, 10);
// other blocks
TEST_ASSERT_EQUAL(
BUNDLE_BLOCK_FLAG_DISCARD_IF_UNPROC,
b->blocks->data->flags
);
bundle_free(b);
}
TEST(bundle6ParserSerializer, parse_cbhe)
{
struct bundle6_parser p;
bundle6_parser_init(&p, verify_and_free_ipn_cbhe_bundle, NULL);
bundle6_parser_read(
&p,
ION_TEST_BUNDLE_IPN_CBHE,
sizeof(ION_TEST_BUNDLE_IPN_CBHE)
);
TEST_ASSERT_EQUAL(PARSER_STATUS_DONE, p.basedata->status);
bundle6_parser_reset(&p);
TEST_ASSERT_EQUAL(PARSER_STATUS_GOOD, p.basedata->status);
}
static enum ud3tn_result write_fail(void *cla_obj, const void *data,
const size_t len)
{
int *counter = cla_obj;
(*counter)++;
return UD3TN_FAIL;
}
TEST(bundle6ParserSerializer, serialize_write_fail)
{
int counter = 0;
TEST_ASSERT_EQUAL(UD3TN_FAIL,
bundle6_serialize(b, write_fail, &counter));
TEST_ASSERT_EQUAL(1, counter);
}
TEST_GROUP_RUNNER(bundle6ParserSerializer)
{
RUN_TEST_CASE(bundle6ParserSerializer, parse_and_serialize);
RUN_TEST_CASE(bundle6ParserSerializer, parse_cbhe);
RUN_TEST_CASE(bundle6ParserSerializer, serialize_write_fail);
}