/*
* xdr.c
* -----
* Serialization/deserialization routines, using XDR (RFC 4506) encoding.
* These functions are not part of the public libhal API.
*
* Copyright (c) 2016-2018, NORDUnet A/S All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the NORDUnet nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h> /* ptrdiff_t */
#include <string.h> /* memcpy, memset */
#include "hal.h"
#include "hal_internal.h" /* htonl/ntohl */
#include "xdr_internal.h"
static int verbose = 0;
/* suppress assert() error messages */
void hal_log(const hal_log_level_t level, const char *format, ...)
{
}
#define DEFINE_HAL_ERROR(_code_,_text_) #_code_,
static char *err_name[] = { HAL_ERROR_LIST };
#undef DEFINE_HAL_ERROR
static void hexdump(uint8_t *buf, uint32_t len)
{
for (uint32_t i = 0; i < len; ++i) {
printf("%02x", buf[i]);
if (i < len - 1)
printf(" ");
}
}
#define test(name, result, expected) \
if ((err = result) != expected) { \
if (!verbose) printf("%s: ", func); \
printf("%s test returned %s, expected %s\n", \
name, err_name[err], err_name[expected]); \
++nerr; \
}
#define test_value(val, exp) \
if (val != exp) { \
if (!verbose) printf("%s: ", func); \
printf("value = %u, expected %u\n", val, exp); \
++nerr; \
}
#define test_len(len, exp) \
if (len != exp) { \
if (!verbose) printf("%s: ", func); \
printf("len = %lu, expected %u\n", len, exp); \
++nerr; \
}
#define test_memcmp(buf, exp, len) \
if (memcmp(buf, exp, len) != 0) { \
if (!verbose) printf("%s: ", func); \
printf("buffer = ["); \
hexdump(buf, len); \
printf("], expected ["); \
hexdump(exp, len); \
printf("]\n"); \
++nerr; \
}
#define test_bufptr(bfp, exp) \
if (bfp != exp) { \
if (!verbose) printf("%s: ", func); \
printf("buf ptr = %p, expected %p\n", bfp, exp); \
++nerr; \
}
static int test_hal_xdr_encode_int(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
uint8_t *null = NULL;
uint8_t buf[4] = {0};
uint8_t *bufptr = buf;
uint8_t *limit = buf + sizeof(buf);
uint8_t exp[4] = { 0x00, 0x11, 0x22, 0x33 };
uint32_t value = 0x00112233;
const char *func = "hal_xdr_encode_int";
if (verbose)
printf("%s... ", func);
test("null outbuf", hal_xdr_encode_int(NULL, limit, value), HAL_ERROR_ASSERTION_FAILED);
test("null outbuf", hal_xdr_encode_int(&null, limit, value), HAL_ERROR_ASSERTION_FAILED);
test("null limit", hal_xdr_encode_int(&bufptr, NULL, value), HAL_ERROR_ASSERTION_FAILED);
test("outbuf overflow", hal_xdr_encode_int(&bufptr, buf, value), HAL_ERROR_XDR_BUFFER_OVERFLOW);
test("outbuf overflow", hal_xdr_encode_int(&bufptr, buf + 3, value), HAL_ERROR_XDR_BUFFER_OVERFLOW);
test("valid write", hal_xdr_encode_int(&bufptr, limit, value), HAL_OK);
test_memcmp(buf, exp, sizeof(exp));
test_bufptr(bufptr, buf + 4);
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
static int test_hal_xdr_decode_int(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
const uint8_t *null = NULL;
const uint8_t buf[4] = { 0x00, 0x11, 0x22, 0x33 };
const uint8_t *bufptr = buf;
const uint8_t * const limit = buf + sizeof(buf);
uint32_t value = 0;
const uint32_t exp = 0x00112233;
const char *func = "hal_xdr_decode_int";
if (verbose)
printf("%s... ", func);
test("null inbuf", hal_xdr_decode_int(NULL, limit, &value), HAL_ERROR_ASSERTION_FAILED);
test("null inbuf", hal_xdr_decode_int(&null, limit, &value), HAL_ERROR_ASSERTION_FAILED);
test("null limit", hal_xdr_decode_int(&bufptr, NULL, &value), HAL_ERROR_ASSERTION_FAILED);
test("null value", hal_xdr_decode_int(&bufptr, limit, NULL), HAL_ERROR_ASSERTION_FAILED);
test("inbuf overflow", hal_xdr_decode_int(&bufptr, buf, &value), HAL_ERROR_XDR_BUFFER_OVERFLOW);
test("inbuf overflow", hal_xdr_decode_int(&bufptr, buf + 3, &value), HAL_ERROR_XDR_BUFFER_OVERFLOW);
test("valid read", hal_xdr_decode_int(&bufptr, limit, &value), HAL_OK);
test_value(value, exp);
test_bufptr(bufptr, buf + 4);
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
static int test_hal_xdr_decode_int_peek(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
const uint8_t buf[4] = { 0x00, 0x11, 0x22, 0x33 };
const uint8_t *bufptr = buf;
const uint8_t * const limit = buf + sizeof(buf);
uint32_t value = 0;
const uint32_t exp = 0x00112233;
const char *func = "hal_xdr_decode_int_peek";
if (verbose)
printf("%s... ", func);
test("valid read", hal_xdr_decode_int_peek(&bufptr, limit, &value), HAL_OK);
test_value(value, exp);
test_bufptr(bufptr, buf);
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
static int test_hal_xdr_encode_fixed_opaque(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
uint8_t *null = NULL;
uint8_t buf[8];
uint8_t *bufptr = buf;
uint8_t *limit = buf + sizeof(buf);
uint8_t src[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
uint8_t exp3[4] = { 0x00, 0x11, 0x22, 0x00 };
uint8_t exp4[4] = { 0x00, 0x11, 0x22, 0x33 };
uint8_t exp5[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 };
const char *func = "hal_xdr_encode_fixed_opaque";
if (verbose)
printf("%s... ", func);
test("null outbuf", hal_xdr_encode_fixed_opaque(NULL, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("null outbuf", hal_xdr_encode_fixed_opaque(&null, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("null limit", hal_xdr_encode_fixed_opaque(&bufptr, NULL, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("null value", hal_xdr_encode_fixed_opaque(&bufptr, limit, NULL, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("outbuf overflow", hal_xdr_encode_fixed_opaque(&bufptr, buf, src, sizeof(src)), HAL_ERROR_XDR_BUFFER_OVERFLOW);
memset(buf, 0xff, sizeof(buf));
test("write 3", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 3), HAL_OK);
test_memcmp(buf, exp3, sizeof(exp3));
test_bufptr(bufptr, buf + 4);
bufptr = buf;
memset(buf, 0xff, sizeof(buf));
test("write 4", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 4), HAL_OK);
test_memcmp(buf, exp4, sizeof(exp4));
test_bufptr(bufptr, buf + 4)
bufptr = buf;
memset(buf, 0xff, sizeof(buf));
test("write 5", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 5), HAL_OK);
test_memcmp(buf, exp5, sizeof(exp5));
test_bufptr(bufptr, buf + 8);
bufptr = buf;
memset(buf, 0xff, sizeof(buf));
test("write 8", hal_xdr_encode_fixed_opaque(&bufptr, limit, src, 8), HAL_OK);
test_memcmp(buf, src, sizeof(src));
test_bufptr(bufptr, buf + 8)
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
static int test_hal_xdr_decode_fixed_opaque(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
const uint8_t *null = NULL;
const uint8_t buf[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
const uint8_t *bufptr = buf;
const uint8_t *limit = buf + sizeof(buf);
uint8_t value[8];
uint8_t exp3[4] = { 0x00, 0x11, 0x22, 0x00 };
uint8_t exp4[4] = { 0x00, 0x11, 0x22, 0x33 };
uint8_t exp5[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 };
const char *func = "hal_xdr_decode_fixed_opaque";
if (verbose)
printf("%s... ", func);
test("null inbuf", hal_xdr_decode_fixed_opaque(NULL, limit, value, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("null inbuf", hal_xdr_decode_fixed_opaque(&null, limit, value, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("null limit", hal_xdr_decode_fixed_opaque(&bufptr, NULL, value, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("null value", hal_xdr_decode_fixed_opaque(&bufptr, limit, NULL, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("inbuf overflow", hal_xdr_decode_fixed_opaque(&bufptr, buf, value, sizeof(value)), HAL_ERROR_XDR_BUFFER_OVERFLOW);
memset(value, 0xff, sizeof(value));
test("read 3", hal_xdr_decode_fixed_opaque(&bufptr, limit, value, 3), HAL_OK);
test_memcmp(value, exp3, sizeof(exp3));
test_bufptr(bufptr, buf + 4);
bufptr = buf;
memset(value, 0xff, sizeof(value));
test("read 4", hal_xdr_decode_fixed_opaque(&bufptr, limit, value, 4), HAL_OK);
test_memcmp(value, exp4, sizeof(exp4));
test_bufptr(bufptr, buf + 4);
bufptr = buf;
memset(value, 0xff, sizeof(value));
test("read 5", hal_xdr_decode_fixed_opaque(&bufptr, limit, value, 5), HAL_OK);
test_memcmp(value, exp5, sizeof(exp5));
test_bufptr(bufptr, buf + 8);
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
static int test_hal_xdr_encode_variable_opaque(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
uint8_t *null = NULL;
uint8_t buf[12];
uint8_t *bufptr = buf;
uint8_t *limit = buf + sizeof(buf);
uint8_t src[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
uint8_t exp3[8] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x11, 0x22, 0x00 };
uint8_t exp4[8] = { 0x00, 0x00, 0x00, 0x04, 0x00, 0x11, 0x22, 0x33 };
uint8_t exp5[12] = { 0x00, 0x00, 0x00, 0x05, 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 };
uint8_t exp8[12] = { 0x00, 0x00, 0x00, 0x08, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
const char *func = "hal_xdr_encode_variable_opaque";
if (verbose)
printf("%s... ", func);
test("null outbuf", hal_xdr_encode_variable_opaque(NULL, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("null outbuf", hal_xdr_encode_variable_opaque(&null, limit, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("null limit", hal_xdr_encode_variable_opaque(&bufptr, NULL, src, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("null value", hal_xdr_encode_variable_opaque(&bufptr, limit, NULL, sizeof(src)), HAL_ERROR_ASSERTION_FAILED);
test("outbuf overflow", hal_xdr_encode_variable_opaque(&bufptr, buf, src, sizeof(src)), HAL_ERROR_XDR_BUFFER_OVERFLOW);
memset(buf, 0xff, sizeof(buf));
test("write 3", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 3), HAL_OK);
test_memcmp(buf, exp3, sizeof(exp3));
test_bufptr(bufptr, buf + 8);
bufptr = buf;
memset(buf, 0xff, sizeof(buf));
test("write 4", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 4), HAL_OK);
test_memcmp(buf, exp4, sizeof(exp4));
test_bufptr(bufptr, buf + 8)
bufptr = buf;
memset(buf, 0xff, sizeof(buf));
test("write 5", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 5), HAL_OK);
test_memcmp(buf, exp5, sizeof(exp5));
test_bufptr(bufptr, buf + 12);
bufptr = buf;
memset(buf, 0xff, sizeof(buf));
test("write 8", hal_xdr_encode_variable_opaque(&bufptr, limit, src, 8), HAL_OK);
test_memcmp(buf, exp8, sizeof(exp8));
test_bufptr(bufptr, buf + 12)
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
static int test_hal_xdr_decode_variable_opaque(void)
{
hal_error_t err = HAL_OK;
int nerr = 0;
const uint8_t *null = NULL;
uint8_t buf[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
const uint8_t *bufptr = buf;
const uint8_t *limit = buf + sizeof(buf);
uint8_t value[12];
size_t len;
uint8_t exp3[4] = { 0x00, 0x11, 0x22, 0x00 };
uint8_t exp4[4] = { 0x00, 0x11, 0x22, 0x33 };
uint8_t exp5[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00 };
uint8_t exp8[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
const char *func = "hal_xdr_decode_variable_opaque";
if (verbose)
printf("%s... ", func);
test("null inbuf", hal_xdr_decode_variable_opaque(NULL, limit, value, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("null inbuf", hal_xdr_decode_variable_opaque(&null, limit, value, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("null limit", hal_xdr_decode_variable_opaque(&bufptr, NULL, value, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("null value", hal_xdr_decode_variable_opaque(&bufptr, limit, NULL, &len, sizeof(value)), HAL_ERROR_ASSERTION_FAILED);
test("inbuf overflow", hal_xdr_decode_variable_opaque(&bufptr, buf, value, &len, sizeof(value)), HAL_ERROR_XDR_BUFFER_OVERFLOW);
buf[3] = 0x03;
memset(value, 0xff, sizeof(value));
test("read 3", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK);
test_len(len, 3);
test_memcmp(value, exp3, sizeof(exp3));
test_bufptr(bufptr, buf + 8);
bufptr = buf;
buf[3] = 0x04;
memset(value, 0xff, sizeof(value));
test("read 4", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK);
test_len(len, 4);
test_memcmp(value, exp4, sizeof(exp4));
test_bufptr(bufptr, buf + 8);
bufptr = buf;
buf[3] = 0x05;
memset(value, 0xff, sizeof(value));
test("read 5", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK);
test_len(len, 5);
test_memcmp(value, exp5, sizeof(exp5));
test_bufptr(bufptr, buf + 12);
bufptr = buf;
buf[3] = 0x08;
memset(value, 0xff, sizeof(value));
test("read 8", hal_xdr_decode_variable_opaque(&bufptr, limit, value, &len, sizeof(value)), HAL_OK);
test_len(len, 8);
test_memcmp(value, exp8, sizeof(exp8));
test_bufptr(bufptr, buf + 12);
if (verbose && nerr == 0)
printf("PASS\n");
return nerr;
}
int main(int argc, char *argv[])
{
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'v')
verbose = 1;
int nerr = 0;
nerr += test_hal_xdr_encode_int();
nerr += test_hal_xdr_decode_int();
nerr += test_hal_xdr_decode_int_peek();
nerr += test_hal_xdr_encode_fixed_opaque();
nerr += test_hal_xdr_decode_fixed_opaque();
nerr += test_hal_xdr_encode_variable_opaque();
nerr += test_hal_xdr_decode_variable_opaque();
if (nerr)
printf("%d failures\n", nerr);
return nerr;
}