mirror of
https://gitlab.com/d3tn/ud3tn.git
synced 2026-08-13 12:33:27 +02:00
In outgoing status reports, previously, we did not send timestamps, even in case they were requested for BPv7 bundles. This refactors the corresponding functions to generate status reports, so we assign the proper timestamp depending on the status flag. Note that we never supported sending a status report capturing multiple events at once -- only the BPv7 SR serializer supports the generation. Signed-off-by: Felix Walter <felix.walter@d3tn.com>
394 lines
10 KiB
C
394 lines
10 KiB
C
// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
|
|
#include "bundle6/create.h"
|
|
#include "bundle6/reports.h"
|
|
#include "bundle6/serializer.h"
|
|
#include "bundle6/parser.h"
|
|
|
|
#include "ud3tn/bundle.h"
|
|
#include "ud3tn/eid.h"
|
|
#include "ud3tn/result.h"
|
|
#include "ud3tn/report_manager.h"
|
|
|
|
#include "platform/hal_time.h"
|
|
|
|
#include "testud3tn_unity.h"
|
|
#include "testud3tn_eid_helpers.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
|
|
static const char test_payload[] = "PAYLOAD";
|
|
static struct bundle *some_bundle;
|
|
static bool verify_ok;
|
|
|
|
static const uint64_t creation_timestamp_s = 658489863; // 2020-11-12T09:51:03+00:00
|
|
static const uint64_t lifetime_s = 42;
|
|
|
|
TEST_GROUP(bundle6ParserSerializer);
|
|
|
|
TEST_SETUP(bundle6ParserSerializer)
|
|
{
|
|
char *payload = malloc(sizeof(test_payload));
|
|
|
|
memcpy(payload, test_payload, sizeof(test_payload));
|
|
some_bundle = bundle6_create_local(
|
|
payload,
|
|
sizeof(test_payload),
|
|
EID_DTN_UD3TN_AGENT,
|
|
EID_DTN_UD3TN_AGENT2,
|
|
EID_DTN_UD3TN_AGENT,
|
|
creation_timestamp_s * 1000, 1, lifetime_s * 1000,
|
|
BUNDLE_FLAG_REPORT_DELIVERY |
|
|
BUNDLE_V6_FLAG_CUSTODY_TRANSFER_REQUESTED
|
|
);
|
|
some_bundle->current_custodian = eid_dup(EID_NULL_DTN);
|
|
|
|
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 eid_list *eid_list = malloc(sizeof(struct eid_list));
|
|
|
|
eid_list->eid = eid_dup(EID_IPN_11);
|
|
eid_list->next = NULL;
|
|
block->eid_refs = eid_list;
|
|
some_bundle->blocks->next = bundle_block_entry_create(block);
|
|
some_bundle->payload_block->flags = BUNDLE_BLOCK_FLAG_NONE;
|
|
}
|
|
|
|
TEST_TEAR_DOWN(bundle6ParserSerializer)
|
|
{
|
|
bundle_free(some_bundle);
|
|
}
|
|
|
|
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(eid_eq(EID_DTN_UD3TN_AGENT, b->source));
|
|
TEST_ASSERT(eid_eq(EID_DTN_UD3TN_AGENT2, b->destination));
|
|
TEST_ASSERT(eid_eq(EID_DTN_UD3TN_AGENT, b->report_to));
|
|
TEST_ASSERT(eid_eq(EID_NULL_DTN, 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_NULL(b->blocks->next->data->eid_refs->next);
|
|
TEST_ASSERT(eid_eq(
|
|
EID_IPN_11,
|
|
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(some_bundle);
|
|
TEST_ASSERT_TRUE(verify_ok);
|
|
|
|
const size_t serialized_size_before = bundle_get_serialized_size(some_bundle);
|
|
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(some_bundle, _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_free(p.bundle);
|
|
free(p.basedata);
|
|
}
|
|
|
|
// 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(eid_eq(
|
|
(struct eid){
|
|
.scheme = EID_SCHEME_IPN,
|
|
.ipn_eid = (struct ipn_eid){
|
|
.fully_qualified_node_number = 3,
|
|
.service_number = 1,
|
|
},
|
|
},
|
|
b->destination
|
|
));
|
|
TEST_ASSERT(eid_is_null(b->source));
|
|
TEST_ASSERT(eid_is_null(b->report_to));
|
|
TEST_ASSERT(eid_is_null(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);
|
|
bundle_free(p.bundle);
|
|
free(p.basedata);
|
|
}
|
|
|
|
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(some_bundle, write_fail, &counter));
|
|
TEST_ASSERT_EQUAL(1, counter);
|
|
}
|
|
|
|
TEST(bundle6ParserSerializer, serialize_and_parse_status_report)
|
|
{
|
|
const uint64_t TIMESTAMP = creation_timestamp_s * 1000 + 5000;
|
|
struct bundle *const sr_bundle = bundle6_generate_status_report(
|
|
some_bundle,
|
|
BUNDLE_SR_FLAG_BUNDLE_DELETED,
|
|
BUNDLE_SR_REASON_NO_KNOWN_ROUTE,
|
|
EID_DTN_UD3TN,
|
|
TIMESTAMP
|
|
);
|
|
|
|
TEST_ASSERT_NOT_NULL(sr_bundle);
|
|
TEST_ASSERT_EQUAL(6, sr_bundle->protocol_version);
|
|
TEST_ASSERT(eid_eq(EID_DTN_UD3TN, sr_bundle->source));
|
|
TEST_ASSERT(eid_eq(some_bundle->report_to, sr_bundle->destination));
|
|
TEST_ASSERT_EQUAL_UINT64(TIMESTAMP, sr_bundle->creation_timestamp_ms);
|
|
TEST_ASSERT(HAS_FLAG(sr_bundle->proc_flags, BUNDLE_FLAG_ADMINISTRATIVE_RECORD));
|
|
TEST_ASSERT_EQUAL_UINT64(
|
|
(creation_timestamp_s + lifetime_s) * 1000 - TIMESTAMP,
|
|
sr_bundle->lifetime_ms
|
|
);
|
|
|
|
struct bundle_administrative_record *const ar = bundle6_parse_administrative_record(
|
|
sr_bundle->payload_block->data,
|
|
sr_bundle->payload_block->length
|
|
);
|
|
|
|
TEST_ASSERT_NOT_NULL(ar);
|
|
TEST_ASSERT_NOT_NULL(ar->status_report);
|
|
TEST_ASSERT_EQUAL(BUNDLE_SR_FLAG_BUNDLE_DELETED, ar->status_report->status);
|
|
TEST_ASSERT_EQUAL(BUNDLE_SR_REASON_NO_KNOWN_ROUTE, ar->status_report->reason);
|
|
TEST_ASSERT_EQUAL_UINT64(TIMESTAMP, ar->status_report->bundle_deleted_time);
|
|
TEST_ASSERT_EQUAL_UINT64(0, ar->status_report->bundle_delivered_time);
|
|
TEST_ASSERT_EQUAL_UINT64(0, ar->status_report->bundle_forwarded_time);
|
|
TEST_ASSERT_EQUAL_UINT64(0, ar->status_report->bundle_received_time);
|
|
TEST_ASSERT_EQUAL_UINT64(some_bundle->creation_timestamp_ms,
|
|
ar->bundle_creation_timestamp_ms);
|
|
TEST_ASSERT_EQUAL_UINT64(some_bundle->sequence_number,
|
|
ar->bundle_sequence_number);
|
|
TEST_ASSERT(eid_eq(some_bundle->source, ar->bundle_source_eid));
|
|
|
|
free_administrative_record(ar);
|
|
bundle_free(sr_bundle);
|
|
}
|
|
|
|
TEST_GROUP_RUNNER(bundle6ParserSerializer)
|
|
{
|
|
RUN_TEST_CASE(bundle6ParserSerializer, parse_and_serialize);
|
|
RUN_TEST_CASE(bundle6ParserSerializer, parse_cbhe);
|
|
RUN_TEST_CASE(bundle6ParserSerializer, serialize_write_fail);
|
|
RUN_TEST_CASE(bundle6ParserSerializer, serialize_and_parse_status_report);
|
|
}
|