xrdp/tests/libipm/test_libipm_send_calls.c
2022-03-15 10:23:27 +00:00

507 lines
16 KiB
C

#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include <unistd.h>
#include <ctype.h>
#include "libipm.h"
#include "os_calls.h"
#include "string_calls.h"
#include "trans.h"
#include "test_libipm.h"
/* Random(ish) values for test_libipm_append_all_test */
#define ALL_TEST_y_VALUE 45
#define ALL_TEST_b_VALUE 0
#define ALL_TEST_n_VALUE -14
#define ALL_TEST_q_VALUE 327
#define ALL_TEST_i_VALUE -100000
#define ALL_TEST_u_VALUE 100000
#define ALL_TEST_x_VALUE -4000000000L
#define ALL_TEST_t_VALUE 8000000000L
#define ALL_TEST_s_VALUE \
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'
#define ALL_TEST_B_VALUE 'a', 'z', 'A', 'Z', '0', '9', '#'
/* This macro generates two unsigned char values, separated by a comma,
* representing a 2's complement little-endian 16-bit integer */
#define BITS16_LE(x) ((x) & 0xff), (((unsigned int)(x) >> 8) & 0xff)
/* This macro generates four unsigned char values, separated by a comma,
* representing a 2's complement little-endian 32-bit integer */
#define BITS32_LE(x) BITS16_LE((x) & 0xffff), \
BITS16_LE(((unsigned int)(x) >> 16) & 0xffff)
/* This macro generates eight unsigned char values, separated by a comma,
* representing a 2's complement little-endian 64-bit integer */
#define BITS64_LE(x) BITS32_LE((uint64_t)(x) & 0xffffffff), \
BITS32_LE(((uint64_t)(x) >> 32) & 0xffffffff)
/* Expected buffer contents for test_libipm_append_all_test */
static const unsigned char all_test_expected_buff[] =
{
BITS16_LE(LIBIPM_VERSION),
BITS16_LE(73), /* Header : message length */
BITS16_LE(LIBIPM_FAC_TEST),
BITS16_LE(TEST_MESSAGE_NO),
BITS32_LE(0),
/* ------------------- */
'y', ALL_TEST_y_VALUE,
'b', ALL_TEST_b_VALUE,
'n', BITS16_LE(ALL_TEST_n_VALUE),
'q', BITS16_LE(ALL_TEST_q_VALUE),
'i', BITS32_LE(ALL_TEST_i_VALUE),
'u', BITS32_LE(ALL_TEST_u_VALUE),
'x', BITS64_LE(ALL_TEST_x_VALUE),
't', BITS64_LE(ALL_TEST_t_VALUE),
/* String + terminator */
's', ALL_TEST_s_VALUE,
/* Fixed size block */
'B', BITS16_LE(7) /* length */, ALL_TEST_B_VALUE
};
/* Type used to map small test values (i.e. simple types that fit in an int)
* to expected status codes if we try to output them for a given tyoe */
struct int_test_value
{
int value;
enum libipm_status expected_status;
};
/***************************************************************************//**
* Compares the data in a stream against an expected data block
*
* @param s Stream to check
* @param expdata Expected data
* @aram explen Expected data len
*/
static void
check_stream_data_eq(const struct stream *s,
const unsigned char *expected_data,
unsigned int expected_len)
{
check_binary_data_eq((unsigned char *)s->data,
(unsigned int)(s->end - s->data),
expected_data,
expected_len);
}
/***************************************************************************//**
* Value checks for small types (i.e. those that fit in an 'int' */
static void
test_small_type_values(char typechar,
const struct int_test_value v[], unsigned int count)
{
unsigned int i;
enum libipm_status status;
char format[] = { typechar, '\0'};
for (i = 0 ; i < count; ++i)
{
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO,
format, v[i].value);
if (status != v[i].expected_status)
{
ck_abort_msg("Test value %d. Expected status %d, got %d",
v[i].value, v[i].expected_status, status);
}
}
}
/***************************************************************************//**
* Checks we can add a simple type right at the end of a buffer, but that
* a buffer overflow is also detected if there's not enough space.
*/
static void
test_append_at_end_of_message(char typechar, unsigned int wire_size)
{
char padding[LIBIPM_MAX_PAYLOAD_SIZE] = {0};
struct libipm_fsb desc;
enum libipm_status status;
const char format[] = {'B', typechar, '\0'};
/* Construct a descriptor for a binary object that fills most of
* the output buffer, leaving just enough space for our type at the end.
* Three bytes are needed for the binary descriptor overhead */
desc.data = padding;
desc.datalen = LIBIPM_MAX_PAYLOAD_SIZE - 3 - wire_size;
/* Check we're OK at the end of the buffer... */
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, &desc, 0);
ck_assert_int_eq(status, E_LI_SUCCESS);
/* ..but if the value would overflow the end of the packet it's an error */
++desc.datalen;
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, format, &desc, 0);
ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW);
}
/***************************************************************************//**
* Appends all data types to a transport, and checks the binary data in
* the output stream is as expected */
START_TEST(test_libipm_append_all_test)
{
ck_assert_ptr_ne(g_t_out, NULL);
static char string[] = { ALL_TEST_s_VALUE };
static char binary[] = { ALL_TEST_B_VALUE };
struct libipm_fsb binary_desc = { (void *)binary, sizeof(binary) };
enum libipm_status status;
status = libipm_msg_out_init(
g_t_out, TEST_MESSAGE_NO,
"ybnqiuxtsB",
ALL_TEST_y_VALUE,
ALL_TEST_b_VALUE,
ALL_TEST_n_VALUE,
ALL_TEST_q_VALUE,
ALL_TEST_i_VALUE,
ALL_TEST_u_VALUE,
ALL_TEST_x_VALUE,
ALL_TEST_t_VALUE,
string,
&binary_desc);
ck_assert_int_eq(status, E_LI_SUCCESS);
libipm_msg_out_mark_end(g_t_out);
check_stream_data_eq(
g_t_out->out_s,
all_test_expected_buff, sizeof(all_test_expected_buff));
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'y'
*/
START_TEST(test_libipm_send_y_type)
{
static const struct int_test_value test_values[] =
{
{0, E_LI_SUCCESS},
{255, E_LI_SUCCESS},
{-1, E_LI_BAD_VALUE},
{256, E_LI_BAD_VALUE},
{63336, E_LI_BAD_VALUE},
{2147483647, E_LI_BAD_VALUE}
};
test_small_type_values('y', test_values,
sizeof(test_values) / sizeof(test_values[0]));
test_append_at_end_of_message('y', 2);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'b'
*/
START_TEST(test_libipm_send_b_type)
{
static const struct int_test_value test_values[] =
{
{0, E_LI_SUCCESS},
{1, E_LI_SUCCESS},
{2, E_LI_BAD_VALUE},
{-1, E_LI_BAD_VALUE},
{256, E_LI_BAD_VALUE}
};
test_small_type_values('b', test_values,
sizeof(test_values) / sizeof(test_values[0]));
test_append_at_end_of_message('b', 2);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'n'
*/
START_TEST(test_libipm_send_n_type)
{
static const struct int_test_value test_values[] =
{
{-32768, E_LI_SUCCESS},
{32767, E_LI_SUCCESS},
{-32769, E_LI_BAD_VALUE},
{32768, E_LI_BAD_VALUE},
{2147483647, E_LI_BAD_VALUE}
};
test_small_type_values('n', test_values,
sizeof(test_values) / sizeof(test_values[0]));
test_append_at_end_of_message('n', 3);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'q'
*/
START_TEST(test_libipm_send_q_type)
{
static const struct int_test_value test_values[] =
{
{0, E_LI_SUCCESS},
{65535, E_LI_SUCCESS},
{-1, E_LI_BAD_VALUE},
{65536, E_LI_BAD_VALUE},
{2147483647, E_LI_BAD_VALUE}
};
test_small_type_values('q', test_values,
sizeof(test_values) / sizeof(test_values[0]));
test_append_at_end_of_message('q', 3);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'i'
*/
START_TEST(test_libipm_send_i_type)
{
#if SIZEOF_INT > 4
static const struct int_test_value test_values[] =
{
{-2147483648, E_LI_SUCCESS},
{2147483647, E_LI_SUCCESS},
{-2147483649, E_LI_BAD_VALUE},
{2147483648, E_LI_BAD_VALUE},
};
test_small_type_values('i', test_values,
sizeof(test_values) / sizeof(test_values[0]));
#endif
test_append_at_end_of_message('i', 5);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'u'
*/
START_TEST(test_libipm_send_u_type)
{
#if SIZEOF_INT > 4
static const struct int_test_value test_values[] =
{
{0, E_LI_SUCCESS},
{4294967296, E_LI_SUCCESS},
{-1, E_LI_BAD_VALUE},
{4294967297, E_LI_BAD_VALUE},
};
test_small_type_values('u', test_values,
sizeof(test_values) / sizeof(test_values[0]));
#endif
test_append_at_end_of_message('u', 5);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'x'
*/
START_TEST(test_libipm_send_x_type)
{
test_append_at_end_of_message('x', 9);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 't'
*/
START_TEST(test_libipm_send_t_type)
{
test_append_at_end_of_message('t', 9);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 's'
*/
START_TEST(test_libipm_send_s_type)
{
enum libipm_status status;
/* The maximum string length would be LIBIPM_MAX_PAYLOAD_SIZE-2, as we
* need one char for the 's' type marker, and another for the string
* terminator */
/* Construct a string one character too long to fit in the buffer */
char str[LIBIPM_MAX_PAYLOAD_SIZE];
g_memset(str, 'A', sizeof(str));
str[sizeof(str) - 1] = '\0';
/* A write should overflow... */
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", str);
ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW);
/* .. but a string one character shorter should be OK */
str[sizeof(str) - 2] = '\0';
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", str);
ck_assert_int_eq(status, E_LI_SUCCESS);
/* Check passing a NULL string doesn't crash the program */
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "s", NULL);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
}
END_TEST
/***************************************************************************//**
* Checks various send errors for 'B'
*/
START_TEST(test_libipm_send_B_type)
{
enum libipm_status status;
char bin[LIBIPM_MAX_PAYLOAD_SIZE] = {0};
struct libipm_fsb desc;
/* The maximum binary block length would be LIBIPM_MAX_PAYLOAD_SIZE - 3,
* as we need one char for the 'B' type marker, and two for the length
*
* Construct a descriptor for a binary object that completely fills
* the output buffer */
desc.data = bin;
desc.datalen = LIBIPM_MAX_PAYLOAD_SIZE - 3;
/* Check it fits in the buffer... */
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc);
ck_assert_int_eq(status, E_LI_SUCCESS);
/* ..but one byte bigger, and it won't fit */
++desc.datalen;
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc);
ck_assert_int_eq(status, E_LI_BUFFER_OVERFLOW);
--desc.datalen;
/* Check NULL pointers don't crash the library */
desc.data = NULL;
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", &desc);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, "B", NULL);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
}
END_TEST
/***************************************************************************//**
* Checks send errors for unsupported and unimplemented types
*/
START_TEST(test_libipm_send_bad_types)
{
enum libipm_status status;
enum libipm_status expected_status;
char format[2] = {0};
char c;
for (c = 0x1; c < 0x7f; ++c)
{
if (!isprint(c))
{
continue;
}
if (g_strchr(g_supported_types, c) == NULL)
{
expected_status = E_LI_UNSUPPORTED_TYPE;
}
else if (g_strchr(g_unimplemented_types, c) != NULL)
{
expected_status = E_LI_UNIMPLEMENTED_TYPE;
}
else
{
continue;
}
format[0] = c;
status = libipm_msg_out_init(g_t_out,
TEST_MESSAGE_NO_STRING_NO,
format, NULL);
if (status != expected_status)
{
ck_abort_msg("Output char '%c'. Expected status %d, got %d",
c, expected_status, status);
}
}
}
END_TEST
/***************************************************************************//**
* Checks message erase works as expected
*
* Also calls libipm_msg_out_append() which isn't exercised anywhere else
*/
START_TEST(test_libipm_send_msg_erase)
{
enum libipm_status status;
const char *username = "username";
const char *password = "password";
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, NULL);
ck_assert_int_eq(status, E_LI_SUCCESS);
status = libipm_msg_out_append(g_t_out, "ss", username, password);
ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_ne(does_stream_contain_string(g_t_out->out_s, password), 0);
libipm_msg_out_erase(g_t_out);
ck_assert_int_eq(does_stream_contain_string(g_t_out->out_s, password), 0);
}
END_TEST
/***************************************************************************//**
* Exercises codepaths that shouldn't be called (programming errors)
*/
START_TEST(test_libipm_send_programming_errors)
{
enum libipm_status status;
status = libipm_msg_out_init(g_t_vanilla, TEST_MESSAGE_NO, NULL);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
status = libipm_msg_out_append(g_t_vanilla, "i", 0);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
libipm_msg_out_mark_end(g_t_vanilla); /* No status to check */
status = libipm_msg_out_simple_send(g_t_vanilla, TEST_MESSAGE_NO, "i", 0);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
}
END_TEST
/******************************************************************************/
Suite *
make_suite_test_libipm_send_calls(void)
{
Suite *s;
TCase *tc;
s = suite_create("libipm_send");
tc = tcase_create("libipm_send");
suite_add_tcase(s, tc);
tcase_add_test(tc, test_libipm_append_all_test);
tcase_add_test(tc, test_libipm_send_y_type);
tcase_add_test(tc, test_libipm_send_b_type);
tcase_add_test(tc, test_libipm_send_n_type);
tcase_add_test(tc, test_libipm_send_q_type);
tcase_add_test(tc, test_libipm_send_i_type);
tcase_add_test(tc, test_libipm_send_u_type);
tcase_add_test(tc, test_libipm_send_x_type);
tcase_add_test(tc, test_libipm_send_t_type);
tcase_add_test(tc, test_libipm_send_s_type);
tcase_add_test(tc, test_libipm_send_B_type);
tcase_add_test(tc, test_libipm_send_y_type);
tcase_add_test(tc, test_libipm_send_bad_types);
tcase_add_test(tc, test_libipm_send_msg_erase);
tcase_add_test(tc, test_libipm_send_programming_errors);
return s;
}