ud3tn/components/bundle6/serializer.c
Felix Walter c2fef74ea9 bundle: Allow 64-bit bundle payload lengths
The bundle block length, fragment offset, and total ADU length fields
were using 32-bit uint types, effectively reducing the maximum bundle
payload size to 4 GiB. This changes the field types to 64-bit uint, so
we can support larger bundles.

Signed-off-by: Felix Walter <felix.walter@d3tn.com>
2024-07-15 00:46:10 +02:00

142 lines
4.5 KiB
C

// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
#include "bundle6/sdnv.h"
#include "bundle6/bundle6.h"
#include "bundle6/serializer.h"
#include "ud3tn/result.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#define write_bytes(success_var, bytes, data) do { \
if ((success_var) && write(cla_obj, data, bytes) != UD3TN_OK) \
(success_var) = false; \
} while (0)
#define serialize_u16(success_var, buffer, value) do { \
__typeof__(buffer) *_buffer = &(buffer); \
write_bytes(success_var, sdnv_write_u16(*_buffer, value), *_buffer); \
} while (0)
#define serialize_u32(success_var, buffer, value) do { \
__typeof__(buffer) *_buffer = &(buffer); \
write_bytes(success_var, sdnv_write_u32(*_buffer, value), *_buffer); \
} while (0)
#define serialize_u64(success_var, buffer, value) do { \
__typeof__(buffer) *_buffer = &(buffer); \
write_bytes(success_var, sdnv_write_u64(*_buffer, value), *_buffer); \
} while (0)
struct eid_reference {
uint16_t scheme_offset;
uint16_t ssp_offset;
};
enum ud3tn_result bundle6_serialize(
struct bundle *bundle,
enum ud3tn_result (*write)(void *cla_obj, const void *, const size_t),
void *cla_obj)
{
uint8_t buffer[MAX_SDNV_SIZE];
// Serialize dict
struct bundle6_dict_descriptor *dict_desc = bundle6_calculate_dict(
bundle
);
char *dict = malloc(dict_desc->dict_length_bytes);
if (dict == NULL) {
free(dict_desc);
return UD3TN_FAIL;
}
bundle6_serialize_dictionary(dict, dict_desc);
// Indicates whether the serialization process can continue
bool ok = true;
/* Write version field */
write_bytes(ok, 1, &(bundle->protocol_version));
/* Write SDNV values up to dictionary length */
serialize_u32(ok, buffer, bundle->proc_flags & (
/* Only RFC 5050 flags */
BUNDLE_FLAG_IS_FRAGMENT
| BUNDLE_FLAG_ADMINISTRATIVE_RECORD
| BUNDLE_FLAG_MUST_NOT_BE_FRAGMENTED
| BUNDLE_V6_FLAG_CUSTODY_TRANSFER_REQUESTED
| BUNDLE_V6_FLAG_SINGLETON_ENDPOINT
| BUNDLE_FLAG_ACKNOWLEDGEMENT_REQUESTED
| BUNDLE_V6_FLAG_NORMAL_PRIORITY
| BUNDLE_V6_FLAG_EXPEDITED_PRIORITY
| BUNDLE_FLAG_REPORT_RECEPTION
| BUNDLE_V6_FLAG_REPORT_CUSTODY_ACCEPTANCE
| BUNDLE_FLAG_REPORT_FORWARDING
| BUNDLE_FLAG_REPORT_DELIVERY
| BUNDLE_FLAG_REPORT_DELETION
));
serialize_u32(ok, buffer, bundle->primary_block_length);
serialize_u16(ok, buffer,
dict_desc->destination_eid_info.dict_scheme_offset);
serialize_u16(ok, buffer,
dict_desc->destination_eid_info.dict_ssp_offset);
serialize_u16(ok, buffer,
dict_desc->source_eid_info.dict_scheme_offset);
serialize_u16(ok, buffer,
dict_desc->source_eid_info.dict_ssp_offset);
serialize_u16(ok, buffer,
dict_desc->report_to_eid_info.dict_scheme_offset);
serialize_u16(ok, buffer,
dict_desc->report_to_eid_info.dict_ssp_offset);
serialize_u16(ok, buffer,
dict_desc->custodian_eid_info.dict_scheme_offset);
serialize_u16(ok, buffer,
dict_desc->custodian_eid_info.dict_ssp_offset);
serialize_u64(ok, buffer, bundle->creation_timestamp_ms / 1000);
serialize_u64(ok, buffer, bundle->sequence_number);
serialize_u64(ok, buffer, bundle->lifetime_ms / 1000);
serialize_u16(ok, buffer, dict_desc->dict_length_bytes);
/* Write dictionary byte array */
write_bytes(ok, dict_desc->dict_length_bytes, dict);
/* Write remaining SDNV values */
if (HAS_FLAG(bundle->proc_flags, BUNDLE_FLAG_IS_FRAGMENT)) {
serialize_u64(ok, buffer, bundle->fragment_offset);
serialize_u64(ok, buffer, bundle->total_adu_length);
}
/* Serialize bundle blocks */
struct bundle_block_list *cur_entry = bundle->blocks;
struct endpoint_list *cur_ref;
int eid_idx = 0;
while (ok && cur_entry != NULL) {
write_bytes(ok, 1, &cur_entry->data->type);
serialize_u32(ok, buffer, cur_entry->data->flags);
if (HAS_FLAG(cur_entry->data->flags,
BUNDLE_V6_BLOCK_FLAG_HAS_EID_REF_FIELD)
) {
// Determine the count of refs
int eid_ref_cnt = 0;
for (cur_ref = cur_entry->data->eid_refs; cur_ref;
cur_ref = cur_ref->next, eid_ref_cnt++)
;
serialize_u16(ok, buffer, eid_ref_cnt);
// Write out the refs
for (int c = 0; c < eid_ref_cnt; c++, eid_idx++) {
struct bundle6_eid_info eid_info =
dict_desc->eid_references[c];
serialize_u16(ok, buffer,
eid_info.dict_scheme_offset);
serialize_u16(ok, buffer,
eid_info.dict_ssp_offset);
}
}
serialize_u64(ok, buffer, cur_entry->data->length);
write_bytes(ok, cur_entry->data->length, cur_entry->data->data);
cur_entry = cur_entry->next;
}
free(dict);
free(dict_desc);
return ok ? UD3TN_OK : UD3TN_FAIL;
}