/** *Flushesinputonanon-blockingsocket * *Returnsnumberofbytesread
*/ staticunsignedint
flush_socket(int sck)
{ char buff[1024]; unsignedint result = 0; int status; while (1)
{
status = g_sck_recv(g_t_in->sck, buff, sizeof(buff), 0); if (status < 0)
{ break;
}
result += status;
}
return result;
}
/**
* Waits for an expected incoming message */ staticvoid
check_for_incoming_message(unsignedshort expected_msgno)
{ enum libipm_status status; unsignedshort msgno;
/* Get the message at the other end */
libipm_msg_in_reset(g_t_in);
status = libipm_msg_in_wait_available(g_t_in);
ck_assert_int_eq(status, E_LI_SUCCESS);
/* The same message is still in the buffer. *
* reduce the payload length by the truncate value...*/
msg_size = get_header_field(g_t_out->out_s, HDR_MSG_LEN);
set_header_field(g_t_out->out_s, HDR_MSG_LEN, msg_size - truncate_value);
/* ...and re-send it */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
/* Catch the message at the other end */
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the value */ switch (typechar)
{ case'B': /* For this type, the descriptor is critical to read
* the value */
status = libipm_msg_in_parse(g_t_in, format,
(struct fsb_type *)valueptr); break; default: /* For other types, the value shouldn't be needed, as
* it's only written to if the parse is successful */
status = libipm_msg_in_parse(g_t_in, format,
(struct fsb_type *)NULL); break;
}
ck_assert_int_eq(status, expected_status);
/* There should be 'truncate_value' extra octets left on the input
* socket which wasn't read when we shrunk the header */
istatus = flush_socket(g_t_in->sck);
ck_assert_int_eq(istatus, truncate_value);
/* Put the message size back to its original value, for further tests */
set_header_field(g_t_out->out_s, HDR_MSG_LEN, msg_size);
}
/* The same message is still in the buffer. *
* Save the field value we are going to change, and replace it */
old_val = get_header_field(g_t_out->out_s, field);
set_header_field(g_t_out->out_s, field, test_val);
/* re-send the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
/* Catch the message at the other end. The error is
* reported when we wait for the incoming message */
libipm_msg_in_reset(g_t_in);
status = libipm_msg_in_wait_available(g_t_in);
ck_assert_int_eq(status, E_LI_BAD_HEADER);
/* There should be 5 extra octets ('u' + 32-bit value) left on the input
* socket which wasn't read when we broke the header */
istatus = flush_socket(g_t_in->sck);
ck_assert_int_eq(istatus, 1 + sizeof(uint32_t));
/* Put the message size back to its original value, for further tests */
set_header_field(g_t_out->out_s, field, old_val);
}
/***************************************************************************//**
* As the 'append all' test, but data is sent across a link, demarshalled,
* and validated */
START_TEST(test_libipm_send_recv_all_test)
{
ck_assert_ptr_ne(g_t_out, NULL);
ck_assert_ptr_ne(g_t_in, NULL);
/* variables for received values */
uint8_t y; int b;
int16_t n;
uint16_t q;
int32_t i;
uint32_t u;
int64_t x;
uint64_t t; char *s; int h = -1; char B[sizeof(bin_out)]; char c;
/* The message is small enough to fit in the socket buffer */
status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO, "ybnqiuxtshB",
TEST_y_VALUE,
TEST_b_VALUE,
TEST_n_VALUE,
TEST_q_VALUE,
TEST_i_VALUE,
TEST_u_VALUE,
TEST_x_VALUE,
TEST_t_VALUE,
TEST_s_VALUE,
g_fd,
&binary_desc);
ck_assert_int_eq(status, E_LI_SUCCESS);
/* Catch the message at the other end */
check_for_incoming_message(TEST_MESSAGE_NO);
/* Re-use our descriptor for the receive operation */
binary_desc.data = (void *)&B;
binary_desc.datalen = sizeof(B);
ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_eq(y, TEST_y_VALUE);
ck_assert_int_eq(b, TEST_b_VALUE);
ck_assert_int_eq(n, TEST_n_VALUE);
ck_assert_int_eq(q, TEST_q_VALUE);
ck_assert_int_eq(i, TEST_i_VALUE);
ck_assert_int_eq(u, TEST_u_VALUE);
ck_assert_int_eq(x, TEST_x_VALUE);
ck_assert_int_eq(t, TEST_t_VALUE);
check_binary_data_eq(TEST_s_VALUE, sizeof(TEST_s_VALUE) - 1,
s, g_strlen(s)); /* The file descriptor should not be -1, neither should it be
* the value we sent. It should also point to /dev/zero */
ck_assert_int_ne(h, -1);
ck_assert_int_ne(h, g_fd);
check_fd_is_dev_zero(h);
g_file_close(h);
/* Resend and re-catch the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Modify the message to contain a '2' for the boolean */
c = libipm_msg_in_peek_type(g_t_in);
ck_assert_int_eq(c, 'b'); /* Next type should be a 'b' */
c = *(g_t_in->in_s->p + 1); /* This should be the test value */
ck_assert_int_eq(c, TEST_b_VALUE); /* Check it */
*(g_t_in->in_s->p + 1) = 2;
status = libipm_msg_in_parse( g_t_in, "b", &b);
ck_assert_int_eq(status, E_LI_BAD_VALUE);
/* Resend and re-catch the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Modify the message to contain a '-1' for the boolean */
*(g_t_in->in_s->p + 1) = (char) -1;
status = libipm_msg_in_parse( g_t_in, "b", &b);
ck_assert_int_eq(status, E_LI_BAD_VALUE);
}
END_TEST
/* First, a simple send... */
status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO, "s", TEST_s_VALUE);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the value */
status = libipm_msg_in_parse( g_t_in, "s", &s);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_binary_data_eq(TEST_s_VALUE, sizeof(TEST_s_VALUE) - 1,
s, g_strlen(s));
/* This effectively tests that unterminated strings are not
* passed back to the user */
test_truncated_input_type('s', &s, 1, E_LI_BAD_VALUE);
}
END_TEST
/***************************************************************************//**
* Checks various receive errors for'h'
*/
START_TEST(test_libipm_receive_h_type)
{ enum libipm_status status; int istatus; unsignedint i; int fd_count;
/* Get the number of open file descriptors */ int base_fd_count = get_open_fd_count();
ck_assert_int_gt(base_fd_count, 0);
/* Send the max number of copies of the /dev/zero
* file descriptor */
status = libipm_msg_out_init(g_t_out, TEST_MESSAGE_NO, NULL);
ck_assert_int_eq(status, E_LI_SUCCESS);
for (i = 0 ; i < LIBIPM_MAX_FD_PER_MSG; ++i)
{
status = libipm_msg_out_append(g_t_out, "h", g_fd);
ck_assert_int_eq(status, E_LI_SUCCESS);
}
libipm_msg_out_mark_end(g_t_out);
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the number of file descriptors has gone up as expected */
fd_count = get_open_fd_count();
ck_assert_int_eq(fd_count, base_fd_count + LIBIPM_MAX_FD_PER_MSG);
/* Check half the descriptors work */ for (i = 0 ; i < LIBIPM_MAX_FD_PER_MSG / 2; ++i)
{ int h = -1;
status = libipm_msg_in_parse(g_t_in, "h", &h);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_fd_is_dev_zero(h);
g_file_close(h);
}
/* Close the message without reading the other descriptors */
libipm_msg_in_reset(g_t_in);
/* Check all the file descriptors we received have been closed */
fd_count = get_open_fd_count();
ck_assert_int_eq(fd_count, base_fd_count);
}
END_TEST
/* Check a truncated binary object is rejected */
test_truncated_input_type('B', &binary_desc, 1, E_LI_BUFFER_OVERFLOW);
/* Check a binary object without a complete length field is rejected */
test_truncated_input_type('B', &binary_desc, sizeof(bin_out) + 1,
E_LI_BUFFER_OVERFLOW);
/* Check a binary object with a mismatching FSB length field is rejected */
--binary_desc.datalen;
test_truncated_input_type('B', &binary_desc, 0, E_LI_BAD_VALUE);
++binary_desc.datalen;
/* Check a binary object with a null FSB data field is rejected */
binary_desc.data = NULL;
test_truncated_input_type('B', &binary_desc, 0, E_LI_PROGRAM_ERROR);
test_truncated_input_type('B', NULL, 0, E_LI_PROGRAM_ERROR);
}
END_TEST
/***************************************************************************//**
* Checks for a message with a completely missing type
*/
START_TEST(test_libipm_receive_no_type)
{ enum libipm_status status;
uint32_t u;
/* First, a simple send... */
status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the value */
status = libipm_msg_in_parse( g_t_in, "u", &u);
ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_eq(u, TEST_u_VALUE);
/* Completely remove the type flag and the value from the message */
test_truncated_input_type('u', &u, sizeof(uint32_t) + 1,
E_LI_BUFFER_OVERFLOW);
}
END_TEST
/***************************************************************************//**
* Checks for a message with an unexpected type
*/
START_TEST(test_libipm_receive_unexpected_type)
{ enum libipm_status status; int istatus;
uint32_t u;
int32_t i;
/* First, a simple send... */
status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the value */
status = libipm_msg_in_parse( g_t_in, "u", &u);
ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_eq(u, TEST_u_VALUE);
/* Resend and re-catch the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Try parsing with a type mismatch */
status = libipm_msg_in_parse( g_t_in, "i", &i);
ck_assert_int_eq(status, E_LI_UNEXPECTED_TYPE);
}
END_TEST
/***************************************************************************//**
* Checks for a message with an unsupported type
*/
START_TEST(test_libipm_receive_unsupported_type)
{ enum libipm_status status; int istatus;
uint32_t u; char c;
/* First, a simple send... */
status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO, "u", TEST_u_VALUE);
ck_assert_int_eq(status, E_LI_SUCCESS);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Check the value */
status = libipm_msg_in_parse( g_t_in, "u", &u);
ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_eq(u, TEST_u_VALUE);
/* Resend and re-catch the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
/* Modify the message to contain an unsupported type */
c = libipm_msg_in_peek_type(g_t_in);
ck_assert_int_eq(c, 'u'); /* Next type should be a 'u' */
*g_t_in->in_s->p = 'A'; /* unsupported type */
c = libipm_msg_in_peek_type(g_t_in);
ck_assert_int_eq(c, '?'); /* peek should say this is an error */
status = libipm_msg_in_parse( g_t_in, "A", NULL); /* Parse it anyway */
ck_assert_int_eq(status, E_LI_UNSUPPORTED_TYPE);
}
END_TEST
/***************************************************************************//**
* Checks for a message with an unimplemented type
*/
START_TEST(test_libipm_receive_unimplemented_type)
{ enum libipm_status status; int istatus;
uint32_t u; char c;
/* First, a simple send... */
status = libipm_msg_out_simple_send(
g_t_out, TEST_MESSAGE_NO_STRING_NO, "u", TEST_u_VALUE);
ck_assert_int_eq(status, E_LI_SUCCESS);
/* Check the value */
status = libipm_msg_in_parse( g_t_in, "u", &u);
ck_assert_int_eq(status, E_LI_SUCCESS);
ck_assert_int_eq(u, TEST_u_VALUE);
/* Resend and re-catch the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO_STRING_NO);
/* Try parsing with an unimplemented type.
* To do this we need to modify the type marker in the input stream */
c = libipm_msg_in_peek_type(g_t_in);
ck_assert_int_eq(c, 'u'); /* Next type should be a 'u' */
*g_t_in->in_s->p = 'd'; /* reserved type */
c = libipm_msg_in_peek_type(g_t_in);
ck_assert_int_eq(c, 'd');
status = libipm_msg_in_parse( g_t_in, "d", NULL);
ck_assert_int_eq(status, E_LI_UNIMPLEMENTED_TYPE);
}
END_TEST
ck_assert_int_ne(does_stream_contain_string(g_t_in->in_s, password), 0);
libipm_msg_in_reset(g_t_in);
ck_assert_msg(does_stream_contain_string(g_t_in->in_s, password) == 0, "Auto buffer reset on input not working");
/* The flag should be reset automatically */ /* Resend and re-catch the message */
istatus = trans_force_write(g_t_out);
ck_assert_int_eq(istatus, 0);
check_for_incoming_message(TEST_MESSAGE_NO);
ck_assert_int_ne(does_stream_contain_string(g_t_in->in_s, password), 0);
libipm_msg_in_reset(g_t_in);
ck_assert_msg(does_stream_contain_string(g_t_in->in_s, password) != 0, "LIBIPM_E_MSG_IN_ERASE_AFTER_USE not automatically cleared");
}
END_TEST /***************************************************************************//**
* Exercises codepaths that shouldn't be called (programming errors)
*/
START_TEST(test_libipm_receive_programming_errors)
{ enum libipm_status status; int available;
int32_t dummy;
status = libipm_msg_in_wait_available(g_t_vanilla);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
status = libipm_msg_in_check_available(g_t_vanilla, &available);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
status = libipm_msg_in_parse(g_t_vanilla, "i", &dummy);
ck_assert_int_eq(status, E_LI_PROGRAM_ERROR);
libipm_msg_in_reset(g_t_vanilla); /* No status to check */
}
END_TEST
/******************************************************************************/
Suite *
make_suite_test_libipm_recv_calls(void)
{
Suite *s;
TCase *tc;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.