Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit test of picoquic_provide_stream_data_buffer #1666

Merged
merged 4 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions UnitTest1/unittest1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,13 @@ namespace UnitTest1
{
int ret = stream_rank_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(provide_stream_buffer)
{
int ret = provide_stream_buffer_test();

Assert::AreEqual(ret, 0);
}

Expand Down
13 changes: 1 addition & 12 deletions picoquic/frames.c
Original file line number Diff line number Diff line change
Expand Up @@ -1506,17 +1506,6 @@ uint8_t * picoquic_format_blocked_frames(picoquic_cnx_t* cnx, uint8_t* bytes, ui
/* handling of stream frames
*/

typedef struct st_picoquic_stream_data_buffer_argument_t {
uint8_t* bytes; /* Points to the beginning of the encoding of the stream frame */
size_t byte_index; /* Current index position after encoding type, stream-id and offset */
size_t byte_space; /* Number of bytes available in the packet after the current index */
size_t allowed_space; /* Maximum number of bytes that the application is authorized to write */
size_t length; /* number of bytes that the application commits to write */
int is_fin; /* Whether this is the end of the stream */
int is_still_active; /* whether the stream is still considered active after this call */
uint8_t* app_buffer; /* buffer provided to the application. */
} picoquic_stream_data_buffer_argument_t;

static size_t picoquic_encode_length_of_stream_frame(
uint8_t* bytes, size_t byte_index, size_t byte_space, size_t length, size_t *start_index)
{
Expand Down Expand Up @@ -1573,7 +1562,7 @@ uint8_t* picoquic_provide_stream_data_buffer(void* context, size_t length, int i
return buffer;
}

static uint8_t* picoquic_format_stream_frame_header(uint8_t* bytes, uint8_t* bytes_max, uint64_t stream_id, uint64_t offset)
uint8_t* picoquic_format_stream_frame_header(uint8_t* bytes, uint8_t* bytes_max, uint64_t stream_id, uint64_t offset)
{
uint8_t* bytes0 = bytes;
if ((bytes = picoquic_frames_uint8_encode(bytes, bytes_max, picoquic_frame_type_stream_range_min)) != NULL &&
Expand Down
2 changes: 1 addition & 1 deletion picoquic/packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1351,7 +1351,7 @@ int picoquic_queue_busy_packet(
payload_length = picoquic_aead_encrypt_generic(bytes + header_length,
payload, sizeof(payload), 0, bytes, header_length, aead_ctx);
/* protect the PN */
picoquic_protect_packet_header(bytes, pn_offset, 0x1F, pn_enc_ctx);
picoquic_protect_packet_header(bytes, pn_offset, 0x0F, pn_enc_ctx);
/* Fill up control fields */
sp->length = byte_index + payload_length;
sp->ptype = picoquic_packet_initial;
Expand Down
13 changes: 13 additions & 0 deletions picoquic/picoquic_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1889,8 +1889,21 @@ void picoquic_process_ack_of_frames(picoquic_cnx_t* cnx, picoquic_packet_t* p,
int is_spurious, uint64_t current_time);

/* Coding and decoding of frames */
typedef struct st_picoquic_stream_data_buffer_argument_t {
uint8_t* bytes; /* Points to the beginning of the encoding of the stream frame */
size_t byte_index; /* Current index position after encoding type, stream-id and offset */
size_t byte_space; /* Number of bytes available in the packet after the current index */
size_t allowed_space; /* Maximum number of bytes that the application is authorized to write */
size_t length; /* number of bytes that the application commits to write */
int is_fin; /* Whether this is the end of the stream */
int is_still_active; /* whether the stream is still considered active after this call */
uint8_t* app_buffer; /* buffer provided to the application. */
} picoquic_stream_data_buffer_argument_t;

int picoquic_is_stream_frame_unlimited(const uint8_t* bytes);

uint8_t* picoquic_format_stream_frame_header(uint8_t* bytes, uint8_t* bytes_max, uint64_t stream_id, uint64_t offset);

int picoquic_parse_stream_header(
const uint8_t* bytes, size_t bytes_max,
uint64_t* stream_id, uint64_t* offset, size_t* data_length, int* fin,
Expand Down
1 change: 1 addition & 0 deletions picoquic_t/picoquic_t.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ static const picoquic_test_def_t test_table[] = {
{ "vn_tp", vn_tp_test },
{ "vn_compat", vn_compat_test },
{ "stream_rank", stream_rank_test },
{ "provide_stream_buffer", provide_stream_buffer_test },
{ "transport_param", transport_param_test },
{ "tls_api_sni", tls_api_sni_test },
{ "tls_api_alpn", tls_api_alpn_test },
Expand Down
2 changes: 1 addition & 1 deletion picoquictest/openssl_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ int openssl_cert_test()
openssl_cert_test_one(TEST_CERT3, 2) != 0) {
ret = -1;
}
return 0;
return ret;
}

#endif /* !PTLS_WITHOUT_OPENSSL */
1 change: 1 addition & 0 deletions picoquictest/picoquictest.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ int bad_cnxid_test();
int stream_splay_test();
int stream_output_test();
int stream_rank_test();
int provide_stream_buffer_test();
int not_before_cnxid_test();
int send_stream_blocked_test();
int stream_ack_test();
Expand Down
152 changes: 152 additions & 0 deletions picoquictest/stream0_frame_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,3 +898,155 @@ int stream_rank_test()

return ret;
}

/* Unit test of "picoquic_provide_stream_data_buffer"
*/

static int picoquic_set_stream_buffer_context(picoquic_stream_data_buffer_argument_t * stream_data_context,
uint8_t * bytes, uint8_t * bytes_max, uint64_t stream_id, uint64_t stream_offset)
{
int ret = 0;
uint8_t* bytes0 = bytes;
memset(stream_data_context, 0, sizeof(picoquic_stream_data_buffer_argument_t));
if ((bytes = picoquic_format_stream_frame_header(bytes, bytes_max, stream_id, stream_offset)) == NULL) {
ret = -1;
}
else {
/* Compute the length */
stream_data_context->bytes = bytes0;
stream_data_context->byte_index = bytes - bytes0;
stream_data_context->allowed_space = bytes_max - bytes;
stream_data_context->byte_space = bytes_max - bytes;
stream_data_context->length = 0;
stream_data_context->is_fin = 0;
stream_data_context->is_still_active = 0;
stream_data_context->app_buffer = NULL;
}
return ret;
}

typedef enum {
size_test_full = 0,
size_test_minus_1,
size_test_minus_2,
size_test_minus_3,
size_test_1,
size_test_0,
size_test_too_long,
size_test_last
} size_test_enum;

int provide_stream_buffer_test_one(uint64_t stream_id, uint64_t stream_offset, size_test_enum size_test, int is_fin)
{
uint8_t packet[512];
uint8_t test_data[512];
picoquic_stream_data_buffer_argument_t stream_data_context;
int ret = picoquic_set_stream_buffer_context(&stream_data_context, packet, packet + sizeof(packet), stream_id, stream_offset);
size_t length = 0;

if (ret == 0) {

switch (size_test) {
case size_test_full:
length = stream_data_context.byte_space;
break;
case size_test_minus_1:
length = stream_data_context.byte_space - 1;
break;
case size_test_minus_2:
length = stream_data_context.byte_space - 2;
break;
case size_test_minus_3:
length = stream_data_context.byte_space - 3;
break;
case size_test_1:
length = 1;
break;
case size_test_0:
length = 0;
break;
case size_test_too_long:
length = stream_data_context.byte_space;
stream_data_context.allowed_space = length - 1;
break;
default:
ret = -1;
break;
}
}

if (ret == 0) {
uint8_t * data_ptr = picoquic_provide_stream_data_buffer(&stream_data_context, length, is_fin, 0);

if (size_test == size_test_too_long) {
ret = (data_ptr == NULL) ? 0 : -1;
}
else if (data_ptr == NULL) {
ret = -1;
}
else if (data_ptr + length > packet + sizeof(packet)) {
ret = -1;
}
else {
uint8_t* packet_start = packet;
uint64_t received_stream_id;
uint64_t received_offset;
size_t received_length = 0;
size_t consumed = 0;
int received_fin = 0;

if (length > 0) {
/* set test data value */
for (size_t i = 0; i < length; i++) {
test_data[i] = (uint8_t)(i ^ 0x7f);
}
/* Fill the data space */
memcpy(data_ptr, test_data, length);
}
/* Get the start point of the data frame */
while (*packet_start == picoquic_frame_type_padding && packet_start < packet + sizeof(packet)) {
packet_start++;
}
/* decode the stream header */
if (picoquic_parse_stream_header(packet_start,
sizeof(packet) - (packet_start - packet), &received_stream_id, &received_offset,
&received_length, &received_fin, &consumed) != 0) {
ret = -1;
}
else if (received_stream_id != stream_id ||
received_offset != stream_offset ||
received_length != length ||
received_fin != is_fin) {
ret = -1;
}
else if (length > 0 &&
memcmp(packet_start + consumed, test_data, length) != 0) {
ret = -1;
}
}
}
return ret;
}

int provide_stream_buffer_test()
{
uint64_t stream_ids[4] = { 0, 7, 127, 0x10000 };
uint64_t offsets[4] = { 0, 1, 65, 0x10000 };
int ret = 0;

for (int i_stream = 0; ret == 0 && i_stream < 4; i_stream++) {
for (int i_offset = 0; ret == 0 && i_offset < 4; i_offset++) {
for (int is_fin = 0; ret == 0 && is_fin < 2; is_fin++) {
for (size_test_enum size_test = 0; ret == 0 && size_test < size_test_last; size_test++) {
ret = provide_stream_buffer_test_one(stream_ids[i_stream], offsets[i_offset], size_test, is_fin);
if (ret != 0) {
DBG_PRINTF("Fails for stream %" PRIu64 ", offset %" PRIu64 ", fin %d, test %d",
stream_ids[i_stream], offsets[i_offset], is_fin, size_test);
break;
}
}
}
}
}
return ret;
}
Loading