From ea5f6d56fd8fe3ad71b1b4d264ed0c8bb5e96fd2 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Mon, 11 Dec 2023 00:26:27 -0600 Subject: [PATCH] Update: Socket size_read/size_write checks, result == -1, and explicit passing .generic. Make sure size_read and size_write are not 0. If either is 0, then return F_data_not. Make sure the result checks are "== -1" rather than "< 0". Explicitly pass .generic for the address union. This probably isn't necessary but being explicit seems safer. The memory address of the address union, regardless of the union type being used, is cast to 'struct sockaddr' in most cases. This makes the use of ".generic" very practical. Add documentation comment about F_pipe being returned. Problems with the address unions ".sin_family" must be set or unclear F_pipe errors are returned. I may in a future commit perform this assignment during setup because the "form" parameter makes this practical and reasonable to do. --- level_0/f_socket/c/socket.c | 32 +++++++++++++++------- level_0/f_socket/c/socket.h | 12 ++++++-- level_0/f_socket/tests/unit/c/test-socket-read.c | 24 ++++++++++++++++ level_0/f_socket/tests/unit/c/test-socket-read.h | 7 +++++ .../tests/unit/c/test-socket-read_message.c | 26 ++++++++++++++++++ .../tests/unit/c/test-socket-read_message.h | 7 +++++ .../tests/unit/c/test-socket-read_stream.c | 24 ++++++++++++++++ .../tests/unit/c/test-socket-read_stream.h | 7 +++++ level_0/f_socket/tests/unit/c/test-socket-write.c | 24 ++++++++++++++++ level_0/f_socket/tests/unit/c/test-socket-write.h | 7 +++++ .../tests/unit/c/test-socket-write_message.c | 26 ++++++++++++++++++ .../tests/unit/c/test-socket-write_message.h | 7 +++++ .../tests/unit/c/test-socket-write_stream.c | 24 ++++++++++++++++ .../tests/unit/c/test-socket-write_stream.h | 7 +++++ level_0/f_socket/tests/unit/c/test-socket.c | 6 ++++ 15 files changed, 227 insertions(+), 13 deletions(-) diff --git a/level_0/f_socket/c/socket.c b/level_0/f_socket/c/socket.c index 8289c58..476bc8f 100644 --- a/level_0/f_socket/c/socket.c +++ b/level_0/f_socket/c/socket.c @@ -10,7 +10,7 @@ extern "C" { if (!socket) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ - const int result = accept(socket->id, (struct sockaddr *) &socket->address, &socket->length); + const int result = accept(socket->id, (struct sockaddr *) &socket->address.generic, &socket->length); if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); @@ -495,7 +495,7 @@ extern "C" { if (!socket) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ - if (getpeername(socket->id, (struct sockaddr *) &socket->address, &socket->length) == -1) { + if (getpeername(socket->id, (struct sockaddr *) &socket->address.generic, &socket->length) == -1) { if (errno == EBADF) return F_status_set_error(F_file_descriptor); if (errno == EFAULT) return F_status_set_error(F_buffer); if (errno == EINVAL) return F_status_set_error(F_parameter); @@ -517,9 +517,11 @@ extern "C" { if (!buffer) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ - const ssize_t result = recvfrom(socket->id_data, buffer, socket->size_read, flags, (struct sockaddr *) &socket->address, &socket->length); + if (!socket->size_read) return F_data_not; - if (result < 0) { + const ssize_t result = recvfrom(socket->id_data, buffer, socket->size_read, flags, (struct sockaddr *) &socket->address.generic, &socket->length); + + if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); if (errno == EALREADY) return F_status_set_error(F_complete_not); @@ -556,9 +558,11 @@ extern "C" { if (!header) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ + if (!socket->size_read) return F_data_not; + const ssize_t result = recvmsg(socket->id_data, header, flags); - if (result < 0) { + if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); if (errno == EALREADY) return F_status_set_error(F_complete_not); @@ -595,9 +599,11 @@ extern "C" { if (!buffer) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ + if (!socket->size_read) return F_data_not; + const ssize_t result = recv(socket->id_data, buffer, socket->size_read, flags); - if (result < 0) { + if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); if (errno == EALREADY) return F_status_set_error(F_complete_not); @@ -634,9 +640,11 @@ extern "C" { if (!buffer) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ - const ssize_t result = sendto(socket->id_data, buffer, socket->size_write, flags, (struct sockaddr *) &socket->address, socket->length); + if (!socket->size_write) return F_data_not; - if (result < 0) { + const ssize_t result = sendto(socket->id_data, buffer, socket->size_write, flags, (struct sockaddr *) &socket->address.generic, socket->length); + + if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); if (errno == EALREADY) return F_status_set_error(F_complete_not); @@ -676,9 +684,11 @@ extern "C" { if (!header) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ + if (!socket->size_write) return F_data_not; + const ssize_t result = sendmsg(socket->id_data, header, flags); - if (result < 0) { + if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); if (errno == EALREADY) return F_status_set_error(F_complete_not); @@ -718,9 +728,11 @@ extern "C" { if (!buffer) return F_status_set_error(F_parameter); #endif // _di_level_0_parameter_checking_ + if (!socket->size_write) return F_data_not; + const ssize_t result = send(socket->id_data, buffer, socket->size_write, flags); - if (result < 0) { + if (result == -1) { if (errno == EACCES) return F_status_set_error(F_access_denied); if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block); if (errno == EALREADY) return F_status_set_error(F_complete_not); diff --git a/level_0/f_socket/c/socket.h b/level_0/f_socket/c/socket.h index 66febd2..ce33bf0 100644 --- a/level_0/f_socket/c/socket.h +++ b/level_0/f_socket/c/socket.h @@ -538,6 +538,7 @@ extern "C" { * * @return * F_okay on success. + * F_data_not on success, but read size is 0 and so nothing was read. * * F_access_denied (with error bit) on access denied. * F_complete_not (with error bit) if an existing connection is not yet complete. @@ -587,6 +588,7 @@ extern "C" { * * @return * F_okay on success. + * F_data_not on success, but read size is 0 and so nothing was read. * * F_access_denied (with error bit) on access denied. * F_complete_not (with error bit) if an existing connection is not yet complete. @@ -640,6 +642,7 @@ extern "C" { * * @return * F_okay on success. + * F_data_not on success, but read size is 0 and so nothing was read. * * F_access_denied (with error bit) on access denied. * F_complete_not (with error bit) if an existing connection is not yet complete. @@ -693,6 +696,7 @@ extern "C" { * * @return * F_okay on success. + * F_data_not on success, but write size is 0 and so nothing was written. * * F_access_denied (with error bit) on access denied. * F_address_not (with error bit) if no address is provided and the connection is not "connection-mode". @@ -709,7 +713,7 @@ extern "C" { * F_memory_not (with error bit) if out of memory. * F_option_not (with error bit) if a flag is not supported. * F_parameter (with error bit) if a parameter is invalid. - * F_pipe (with error bit) if the local end of a connection oriented socket is closed or SIGPIPE is received. + * F_pipe (with error bit) if the local end of a connection oriented socket is closed or SIGPIPE is received (Linux might return this isntead if F_connect_not). * F_prohibited (with error bit) if the insufficient privileges to perform send. * F_size (with error bit) if size of message makes atomically sending message impossible on a socket type that requires this to be atomic. * F_socket_not (with error bit) if the ID is not a socket descriptor. @@ -746,6 +750,7 @@ extern "C" { * * @return * F_okay on success. + * F_data_not on success, but write size is 0 and so nothing was written. * * F_access_denied (with error bit) on access denied. * F_address_not (with error bit) if no address is provided and the connection is not "connection-mode". @@ -762,7 +767,7 @@ extern "C" { * F_memory_not (with error bit) if out of memory. * F_option_not (with error bit) if a flag is not supported. * F_parameter (with error bit) if a parameter is invalid. - * F_pipe (with error bit) if the local end of a connection oriented socket is closed or SIGPIPE is received. + * F_pipe (with error bit) if the local end of a connection oriented socket is closed or SIGPIPE is received (Linux might return this isntead if F_connect_not). * F_prohibited (with error bit) if the insufficient privileges to perform send. * F_size (with error bit) if size of message makes atomically sending message impossible on a socket type that requires this to be atomic. * F_socket_not (with error bit) if the ID is not a socket descriptor. @@ -803,6 +808,7 @@ extern "C" { * * @return * F_okay on success. + * F_data_not on success, but write size is 0 and so nothing was written. * * F_access_denied (with error bit) on access denied. * F_address_not (with error bit) if no address is provided and the connection is not "connection-mode". @@ -819,7 +825,7 @@ extern "C" { * F_memory_not (with error bit) if out of memory. * F_option_not (with error bit) if a flag is not supported. * F_parameter (with error bit) if a parameter is invalid. - * F_pipe (with error bit) if the local end of a connection oriented socket is closed or SIGPIPE is received. + * F_pipe (with error bit) if the local end of a connection oriented socket is closed or SIGPIPE is received (Linux might return this isntead if F_connect_not). * F_prohibited (with error bit) if the insufficient privileges to perform send. * F_size (with error bit) if size of message makes atomically sending message impossible on a socket type that requires this to be atomic. * F_socket_not (with error bit) if the ID is not a socket descriptor. diff --git a/level_0/f_socket/tests/unit/c/test-socket-read.c b/level_0/f_socket/tests/unit/c/test-socket-read.c index 71fbfb8..6878350 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-read.c +++ b/level_0/f_socket/tests/unit/c/test-socket-read.c @@ -91,6 +91,30 @@ void test__f_socket_read__parameter_checking(void **state) { } } +void test__f_socket_read__returns_data_not(void **state) { + + char * const buffer = "test"; + + { + f_socket_t socket = f_socket_t_initialize; + socket.size_read = 0; + + const f_status_t status = f_socket_read(&socket, 0, (void *) buffer, 0); + + assert_int_equal(status, F_data_not); + } + + { + size_t length = 0; + f_socket_t socket = f_socket_t_initialize; + socket.size_read = 0; + + const f_status_t status = f_socket_read(&socket, 0, (void *) buffer, &length); + + assert_int_equal(status, F_data_not); + } +} + void test__f_socket_read__works(void **state) { f_socket_t socket = f_socket_t_initialize; diff --git a/level_0/f_socket/tests/unit/c/test-socket-read.h b/level_0/f_socket/tests/unit/c/test-socket-read.h index 1433a0a..0189a7c 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-read.h +++ b/level_0/f_socket/tests/unit/c/test-socket-read.h @@ -25,6 +25,13 @@ extern void test__f_socket_read__fails(void **state); extern void test__f_socket_read__parameter_checking(void **state); /** + * Test that the function returns F_data_not. + * + * @see f_socket_read() + */ +extern void test__f_socket_read__returns_data_not(void **state); + +/** * Test that function works. * * @see f_socket_read() diff --git a/level_0/f_socket/tests/unit/c/test-socket-read_message.c b/level_0/f_socket/tests/unit/c/test-socket-read_message.c index 1f5bfd3..fd65e0f 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-read_message.c +++ b/level_0/f_socket/tests/unit/c/test-socket-read_message.c @@ -94,6 +94,32 @@ void test__f_socket_read_message__parameter_checking(void **state) { } } +void test__f_socket_read_message__returns_data_not(void **state) { + + struct msghdr header; + + memset(&header, 0, sizeof(struct msghdr)); + + { + f_socket_t socket = f_socket_t_initialize; + socket.size_read = 0; + + const f_status_t status = f_socket_read_message(&socket, 0, &header, 0); + + assert_int_equal(status, F_data_not); + } + + { + size_t length = 0; + f_socket_t socket = f_socket_t_initialize; + socket.size_read = 0; + + const f_status_t status = f_socket_read_message(&socket, 0, &header, &length); + + assert_int_equal(status, F_data_not); + } +} + void test__f_socket_read_message__works(void **state) { f_socket_t socket = f_socket_t_initialize; diff --git a/level_0/f_socket/tests/unit/c/test-socket-read_message.h b/level_0/f_socket/tests/unit/c/test-socket-read_message.h index 67883e5..3393b0a 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-read_message.h +++ b/level_0/f_socket/tests/unit/c/test-socket-read_message.h @@ -25,6 +25,13 @@ extern void test__f_socket_read_message__fails(void **state); extern void test__f_socket_read_message__parameter_checking(void **state); /** + * Test that the function returns F_data_not. + * + * @see f_socket_read_message() + */ +extern void test__f_socket_read_message__returns_data_not(void **state); + +/** * Test that function works. * * @see f_socket_read_message() diff --git a/level_0/f_socket/tests/unit/c/test-socket-read_stream.c b/level_0/f_socket/tests/unit/c/test-socket-read_stream.c index e21fb24..d2fa6d0 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-read_stream.c +++ b/level_0/f_socket/tests/unit/c/test-socket-read_stream.c @@ -91,6 +91,30 @@ void test__f_socket_read_stream__parameter_checking(void **state) { } } +void test__f_socket_read_stream__returns_data_not(void **state) { + + char * const buffer = "test"; + + { + f_socket_t socket = f_socket_t_initialize; + socket.size_read = 0; + + const f_status_t status = f_socket_read_stream(&socket, 0, (void *) buffer, 0); + + assert_int_equal(status, F_data_not); + } + + { + size_t length = 0; + f_socket_t socket = f_socket_t_initialize; + socket.size_read = 0; + + const f_status_t status = f_socket_read_stream(&socket, 0, (void *) buffer, &length); + + assert_int_equal(status, F_data_not); + } +} + void test__f_socket_read_stream__works(void **state) { f_socket_t socket = f_socket_t_initialize; diff --git a/level_0/f_socket/tests/unit/c/test-socket-read_stream.h b/level_0/f_socket/tests/unit/c/test-socket-read_stream.h index 67c3c75..1790043 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-read_stream.h +++ b/level_0/f_socket/tests/unit/c/test-socket-read_stream.h @@ -25,6 +25,13 @@ extern void test__f_socket_read_stream__fails(void **state); extern void test__f_socket_read_stream__parameter_checking(void **state); /** + * Test that the function returns F_data_not. + * + * @see f_socket_read_stream() + */ +extern void test__f_socket_read_stream__returns_data_not(void **state); + +/** * Test that function works. * * @see f_socket_read_stream() diff --git a/level_0/f_socket/tests/unit/c/test-socket-write.c b/level_0/f_socket/tests/unit/c/test-socket-write.c index 3b6d8c3..ee791b0 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-write.c +++ b/level_0/f_socket/tests/unit/c/test-socket-write.c @@ -97,6 +97,30 @@ void test__f_socket_write__parameter_checking(void **state) { } } +void test__f_socket_write__returns_data_not(void **state) { + + char * const buffer = "test"; + + { + f_socket_t socket = f_socket_t_initialize; + socket.size_write = 0; + + const f_status_t status = f_socket_write(&socket, 0, (void *) buffer, 0); + + assert_int_equal(status, F_data_not); + } + + { + size_t length = 0; + f_socket_t socket = f_socket_t_initialize; + socket.size_write = 0; + + const f_status_t status = f_socket_write(&socket, 0, (void *) buffer, &length); + + assert_int_equal(status, F_data_not); + } +} + void test__f_socket_write__works(void **state) { f_socket_t socket = f_socket_t_initialize; diff --git a/level_0/f_socket/tests/unit/c/test-socket-write.h b/level_0/f_socket/tests/unit/c/test-socket-write.h index d87c4ea..6a3d344 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-write.h +++ b/level_0/f_socket/tests/unit/c/test-socket-write.h @@ -25,6 +25,13 @@ extern void test__f_socket_write__fails(void **state); extern void test__f_socket_write__parameter_checking(void **state); /** + * Test that the function returns F_data_not. + * + * @see f_socket_write() + */ +extern void test__f_socket_write__returns_data_not(void **state); + +/** * Test that function works. * * @see f_socket_write() diff --git a/level_0/f_socket/tests/unit/c/test-socket-write_message.c b/level_0/f_socket/tests/unit/c/test-socket-write_message.c index c300c39..3056e82 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-write_message.c +++ b/level_0/f_socket/tests/unit/c/test-socket-write_message.c @@ -100,6 +100,32 @@ void test__f_socket_write_message__parameter_checking(void **state) { } } +void test__f_socket_write_message__returns_data_not(void **state) { + + struct msghdr header; + + memset(&header, 0, sizeof(struct msghdr)); + + { + f_socket_t socket = f_socket_t_initialize; + socket.size_write = 0; + + const f_status_t status = f_socket_write_message(&socket, 0, &header, 0); + + assert_int_equal(status, F_data_not); + } + + { + size_t length = 0; + f_socket_t socket = f_socket_t_initialize; + socket.size_write = 0; + + const f_status_t status = f_socket_write_message(&socket, 0, &header, &length); + + assert_int_equal(status, F_data_not); + } +} + void test__f_socket_write_message__works(void **state) { f_socket_t socket = f_socket_t_initialize; diff --git a/level_0/f_socket/tests/unit/c/test-socket-write_message.h b/level_0/f_socket/tests/unit/c/test-socket-write_message.h index b96350f..475dc40 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-write_message.h +++ b/level_0/f_socket/tests/unit/c/test-socket-write_message.h @@ -25,6 +25,13 @@ extern void test__f_socket_write_message__fails(void **state); extern void test__f_socket_write_message__parameter_checking(void **state); /** + * Test that the function returns F_data_not. + * + * @see f_socket_write_message() + */ +extern void test__f_socket_write_message__returns_data_not(void **state); + +/** * Test that function works. * * @see f_socket_write_message() diff --git a/level_0/f_socket/tests/unit/c/test-socket-write_stream.c b/level_0/f_socket/tests/unit/c/test-socket-write_stream.c index f3b6511..744c8aa 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-write_stream.c +++ b/level_0/f_socket/tests/unit/c/test-socket-write_stream.c @@ -97,6 +97,30 @@ void test__f_socket_write_stream__parameter_checking(void **state) { } } +void test__f_socket_write_stream__returns_data_not(void **state) { + + char * const buffer = "test"; + + { + f_socket_t socket = f_socket_t_initialize; + socket.size_write = 0; + + const f_status_t status = f_socket_write_stream(&socket, 0, (void *) buffer, 0); + + assert_int_equal(status, F_data_not); + } + + { + size_t length = 0; + f_socket_t socket = f_socket_t_initialize; + socket.size_write = 0; + + const f_status_t status = f_socket_write_stream(&socket, 0, (void *) buffer, &length); + + assert_int_equal(status, F_data_not); + } +} + void test__f_socket_write_stream__works(void **state) { f_socket_t socket = f_socket_t_initialize; diff --git a/level_0/f_socket/tests/unit/c/test-socket-write_stream.h b/level_0/f_socket/tests/unit/c/test-socket-write_stream.h index 5bc28e5..414146d 100644 --- a/level_0/f_socket/tests/unit/c/test-socket-write_stream.h +++ b/level_0/f_socket/tests/unit/c/test-socket-write_stream.h @@ -25,6 +25,13 @@ extern void test__f_socket_write_stream__fails(void **state); extern void test__f_socket_write_stream__parameter_checking(void **state); /** + * Test that the function returns F_data_not. + * + * @see f_socket_write_stream() + */ +extern void test__f_socket_write_stream__returns_data_not(void **state); + +/** * Test that function works. * * @see f_socket_write_stream() diff --git a/level_0/f_socket/tests/unit/c/test-socket.c b/level_0/f_socket/tests/unit/c/test-socket.c index e521eac..368682b 100644 --- a/level_0/f_socket/tests/unit/c/test-socket.c +++ b/level_0/f_socket/tests/unit/c/test-socket.c @@ -63,21 +63,27 @@ int main(void) { cmocka_unit_test(test__f_socket_option_set__works), cmocka_unit_test(test__f_socket_read__fails), + cmocka_unit_test(test__f_socket_read__returns_data_not), cmocka_unit_test(test__f_socket_read__works), cmocka_unit_test(test__f_socket_read_message__fails), + cmocka_unit_test(test__f_socket_read_message__returns_data_not), cmocka_unit_test(test__f_socket_read_message__works), cmocka_unit_test(test__f_socket_read_stream__fails), + cmocka_unit_test(test__f_socket_read_stream__returns_data_not), cmocka_unit_test(test__f_socket_read_stream__works), cmocka_unit_test(test__f_socket_write__fails), + cmocka_unit_test(test__f_socket_write__returns_data_not), cmocka_unit_test(test__f_socket_write__works), cmocka_unit_test(test__f_socket_write_message__fails), + cmocka_unit_test(test__f_socket_write_message__returns_data_not), cmocka_unit_test(test__f_socket_write_message__works), cmocka_unit_test(test__f_socket_write_stream__fails), + cmocka_unit_test(test__f_socket_write_stream__returns_data_not), cmocka_unit_test(test__f_socket_write_stream__works), cmocka_unit_test(test__f_socket_addressss_destroy_callback__fails), -- 1.8.3.1