diff --git a/interfaces/devdoc/socket_transport_requirements.md b/interfaces/devdoc/socket_transport_requirements.md index ab41945..bd3cf86 100644 --- a/interfaces/devdoc/socket_transport_requirements.md +++ b/interfaces/devdoc/socket_transport_requirements.md @@ -39,6 +39,13 @@ MU_DEFINE_ENUM(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) MU_DEFINE_ENUM(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) +#define SOCKET_ACCEPT_RESULT_VALUES \ + SOCKET_ACCEPT_OK, \ + SOCKET_ACCEPT_ERROR, \ + SOCKET_ACCEPT_NO_CONNECTION + +MU_DEFINE_ENUM(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) + #define SOCKET_TYPE_VALUES \ SOCKET_CLIENT, \ SOCKET_BINDING @@ -59,7 +66,7 @@ MOCKABLE_FUNCTION(, int, socket_transport_connect, SOCKET_TRANSPORT_HANDLE, sock MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socket_transport, uint16_t, port); MOCKABLE_FUNCTION(, void, socket_transport_disconnect, SOCKET_TRANSPORT_HANDLE, socket_transport); -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); MOCKABLE_FUNCTION(, SOCKET_SEND_RESULT, socket_transport_send, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_sent, uint32_t, flags, void*, data); MOCKABLE_FUNCTION(, SOCKET_RECEIVE_RESULT, socket_transport_receive, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_recv, uint32_t, flags, void*, data); @@ -135,7 +142,7 @@ MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socke ### socket_transport_accept ```c -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); ``` `socket_transport_accept` accepts the incoming connections. diff --git a/interfaces/inc/c_pal/socket_transport.h b/interfaces/inc/c_pal/socket_transport.h index bf016b8..bf44aa9 100644 --- a/interfaces/inc/c_pal/socket_transport.h +++ b/interfaces/inc/c_pal/socket_transport.h @@ -36,6 +36,13 @@ MU_DEFINE_ENUM(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) MU_DEFINE_ENUM(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) +#define SOCKET_ACCEPT_RESULT_VALUES \ + SOCKET_ACCEPT_OK, \ + SOCKET_ACCEPT_ERROR, \ + SOCKET_ACCEPT_NO_CONNECTION + +MU_DEFINE_ENUM(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) + #define SOCKET_TYPE_VALUES \ SOCKET_BINDING, \ SOCKET_CLIENT @@ -56,7 +63,7 @@ MOCKABLE_FUNCTION(, int, socket_transport_connect, SOCKET_TRANSPORT_HANDLE, sock MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socket_transport, uint16_t, port); MOCKABLE_FUNCTION(, void, socket_transport_disconnect, SOCKET_TRANSPORT_HANDLE, socket_transport); -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); MOCKABLE_FUNCTION(, SOCKET_SEND_RESULT, socket_transport_send, SOCKET_TRANSPORT_HANDLE, socket_transport, const SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_sent, uint32_t, flags, void*, data); MOCKABLE_FUNCTION(, SOCKET_RECEIVE_RESULT, socket_transport_receive, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_recv, uint32_t, flags, void*, data); diff --git a/interfaces/tests/socket_transport_int/socket_transport_int.c b/interfaces/tests/socket_transport_int/socket_transport_int.c index bef2cf7..23abbe4 100644 --- a/interfaces/tests/socket_transport_int/socket_transport_int.c +++ b/interfaces/tests/socket_transport_int/socket_transport_int.c @@ -45,6 +45,7 @@ typedef struct CHAOS_TEST_SOCKETS_TAG TEST_DEFINE_ENUM_TYPE(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES); +TEST_DEFINE_ENUM_TYPE(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(THREADAPI_RESULT, THREADAPI_RESULT_VALUES); BEGIN_TEST_SUITE(TEST_SUITE_NAME_FROM_CMAKE) @@ -84,7 +85,9 @@ TEST_FUNCTION(send_and_receive_2_buffer_of_2_byte_succeeds) ASSERT_ARE_EQUAL(int, 0, socket_transport_connect(client_socket, "localhost", g_port_num, TEST_CONN_TIMEOUT)); - SOCKET_TRANSPORT_HANDLE incoming_socket = socket_transport_accept(listen_socket); + SOCKET_TRANSPORT_HANDLE incoming_socket; + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_OK, socket_transport_accept(listen_socket, &incoming_socket)); + ASSERT_IS_NOT_NULL(incoming_socket); uint8_t send_payload_1[] = { 0x42, 0x43 }; uint8_t send_payload_2[] = { 0x44, 0x45 }; @@ -187,7 +190,8 @@ TEST_FUNCTION(send_and_receive_random_buffer_of_random_byte_succeeds) ASSERT_ARE_EQUAL(int, 0, socket_transport_connect(client_socket, "localhost", g_port_num, TEST_CONN_TIMEOUT)); - SOCKET_TRANSPORT_HANDLE incoming_socket = socket_transport_accept(listen_socket); + SOCKET_TRANSPORT_HANDLE incoming_socket; + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_OK, socket_transport_accept(listen_socket, &incoming_socket)); ASSERT_IS_NOT_NULL(incoming_socket); uint8_t buffer_count = 8; @@ -245,9 +249,7 @@ static int connect_and_listen_func(void* parameter) { ASSERT_ARE_EQUAL(int, 0, socket_transport_connect(chaos_knight_test->client_socket_handles[i], "localhost", g_port_num, TEST_CONN_TIMEOUT)); - chaos_knight_test->incoming_socket_handles[i] = socket_transport_accept(chaos_knight_test->listen_socket); - - ASSERT_IS_NOT_NULL(chaos_knight_test->incoming_socket_handles[i]); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_OK, socket_transport_accept(chaos_knight_test->listen_socket, &chaos_knight_test->incoming_socket_handles[i])); } return 0; diff --git a/linux/devdoc/socket_transport_linux_requirements.md b/linux/devdoc/socket_transport_linux_requirements.md index fa465eb..c65fb16 100644 --- a/linux/devdoc/socket_transport_linux_requirements.md +++ b/linux/devdoc/socket_transport_linux_requirements.md @@ -31,6 +31,13 @@ MU_DEFINE_ENUM(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) MU_DEFINE_ENUM(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) +#define SOCKET_ACCEPT_RESULT_VALUES \ + SOCKET_ACCEPT_OK, \ + SOCKET_ACCEPT_ERROR, \ + SOCKET_ACCEPT_NO_SOCKET + +MU_DEFINE_ENUM(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) + #define SOCKET_TYPE_VALUES \ SOCKET_CLIENT, \ SOCKET_BINDING @@ -51,7 +58,7 @@ MOCKABLE_FUNCTION(, int, socket_transport_connect, SOCKET_TRANSPORT_HANDLE, sock MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socket_transport, uint16_t, port); MOCKABLE_FUNCTION(, void, socket_transport_disconnect, SOCKET_TRANSPORT_HANDLE, socket_transport); -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); MOCKABLE_FUNCTION(, SOCKET_SEND_RESULT, socket_transport_send, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_sent, uint32_t, flags, void*, data); MOCKABLE_FUNCTION(, SOCKET_RECEIVE_RESULT, socket_transport_receive, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_recv, uint32_t, flags, void*, data); @@ -256,28 +263,30 @@ MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socke ### socket_transport_accept ```c -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); ``` `socket_transport_accept` accepts the incoming connections. -**SOCKET_TRANSPORT_LINUX_11_069: [** If `socket_transport` is `NULL`, `socket_transport_accept` shall fail and return `NULL`. **]** +**SOCKET_TRANSPORT_LINUX_11_069: [** If `socket_transport` is `NULL`, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** -**SOCKET_TRANSPORT_LINUX_11_070: [** If the transport type is not `SOCKET_BINDING`, `socket_transport_accept` shall fail and return `NULL`. **]** +**SOCKET_TRANSPORT_LINUX_11_070: [** If the transport type is not `SOCKET_BINDING`, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_LINUX_11_071: [** `socket_transport_accept` shall call `sm_exec_begin`. **]** -**SOCKET_TRANSPORT_LINUX_11_072: [** If `sm_exec_begin` does not return `SM_EXEC_GRANTED`, `socket_transport_accept` shall fail and return `NULL`. **]** +**SOCKET_TRANSPORT_LINUX_11_072: [** If `sm_exec_begin` does not return `SM_EXEC_GRANTED`, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_LINUX_11_073: [** `socket_transport_accept` shall call `accept` to accept the incoming socket connection. **]** +**SOCKET_TRANSPORT_LINUX_11_084: [** If `errno` is `EAGAIN` or `EWOULDBLOCK`, socket_transport_accept shall return `SOCKET_ACCEPT_NO_CONNECTION`. **]** + **SOCKET_TRANSPORT_LINUX_11_074: [** `socket_transport_accept` shall set the incoming socket to non-blocking. **]** **SOCKET_TRANSPORT_LINUX_11_075: [** `socket_transport_accept` shall allocate a `SOCKET_TRANSPORT` for the incoming connection and call `sm_create` and `sm_open` on the connection. **]** -**SOCKET_TRANSPORT_LINUX_11_076: [** If successful `socket_transport_accept` shall return the allocated `SOCKET_TRANSPORT` of type SOCKET_DATA. **]** +**SOCKET_TRANSPORT_LINUX_11_076: [** If successful `socket_transport_accept` shall assign accepted_socket to be the allocated incoming `SOCKET_TRANSPORT` and return `SOCKET_ACCEPT_OK`. **]** -**SOCKET_TRANSPORT_LINUX_11_077: [** If any failure is encountered, `socket_transport_accept` shall fail and return `NULL`. **]** +**SOCKET_TRANSPORT_LINUX_11_077: [** If any failure is encountered, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_LINUX_11_078: [** `socket_transport_accept` shall call `sm_exec_end`. **]** diff --git a/linux/src/socket_transport_linux.c b/linux/src/socket_transport_linux.c index cfee98b..531d737 100644 --- a/linux/src/socket_transport_linux.c +++ b/linux/src/socket_transport_linux.c @@ -581,22 +581,23 @@ all_ok: return result; } -SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_transport) +SOCKET_ACCEPT_RESULT socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_transport, SOCKET_TRANSPORT_HANDLE* accepting_socket) { - SOCKET_TRANSPORT* result; - // Codes_SOCKET_TRANSPORT_LINUX_11_069: [ If socket_transport is NULL, socket_transport_accept shall fail and return NULL. ] + SOCKET_TRANSPORT* accept_result; + SOCKET_ACCEPT_RESULT result; + // Codes_SOCKET_TRANSPORT_LINUX_11_069: [ If socket_transport is NULL, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] if (socket_transport == NULL) { LogError("Invalid arguments: SOCKET_TRANSPORT_HANDLE socket_transport: %p", socket_transport); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { - // Codes_SOCKET_TRANSPORT_LINUX_11_070: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return NULL. ] + // Codes_SOCKET_TRANSPORT_LINUX_11_070: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] if (socket_transport->type != SOCKET_BINDING) { LogError("Invalid socket type for this API expected: SOCKET_BINDING, actual: %" PRI_MU_ENUM, MU_ENUM_VALUE(SOCKET_TYPE, socket_transport->type)); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { @@ -604,9 +605,9 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t SM_RESULT sm_result = sm_exec_begin(socket_transport->sm); if (sm_result != SM_EXEC_GRANTED) { - // Codes_SOCKET_TRANSPORT_LINUX_11_072: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return NULL. ] + // Codes_SOCKET_TRANSPORT_LINUX_11_072: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] LogError("sm_exec_begin failed : %" PRI_MU_ENUM, MU_ENUM_VALUE(SM_RESULT, sm_result)); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { @@ -618,8 +619,19 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t accepted_socket = accept(socket_transport->socket, (struct sockaddr*)&cli_addr, &client_len); if (accepted_socket == INVALID_SOCKET) { - LogErrorNo("Failure accepting socket"); - result = NULL; + // Codes_SOCKET_TRANSPORT_LINUX_11_084: [ If errno is EAGAIN or EWOULDBLOCK, socket_transport_accept shall return SOCKET_ACCEPT_NO_CONNECTION. ] + if(errno == EAGAIN || errno == EWOULDBLOCK) + { + LogErrorNo("The socket is nonblocking and no connections are present to be accepted."); + result = SOCKET_ACCEPT_NO_CONNECTION; + sm_exec_end(socket_transport->sm); + goto all_ok; + } + else + { + LogErrorNo("Failure accepting socket."); + result = SOCKET_ACCEPT_ERROR; + } } else { @@ -627,7 +639,7 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t if (set_nonblocking(accepted_socket) != 0) { LogError("Failure: setting socket to nonblocking."); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { @@ -637,39 +649,41 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t // Create the socket handle // Codes_SOCKET_TRANSPORT_LINUX_11_075: [ socket_transport_accept shall allocate a SOCKET_TRANSPORT for the incoming connection and call sm_create and sm_open on the connection. ] - result = malloc(sizeof(SOCKET_TRANSPORT)); - if (result == NULL) + accept_result = malloc(sizeof(SOCKET_TRANSPORT)); + if (accept_result == NULL) { LogError("failure allocating SOCKET_TRANSPORT: %zu", sizeof(SOCKET_TRANSPORT)); } else { - result->sm = sm_create("Socket_transport_win32"); - if (result->sm == NULL) + accept_result->sm = sm_create("Socket_transport_win32"); + if (accept_result->sm == NULL) { LogError("Failed calling sm_create in accept, closing incoming socket."); } else { - SM_RESULT open_result = sm_open_begin(result->sm); + SM_RESULT open_result = sm_open_begin(accept_result->sm); if (open_result == SM_EXEC_GRANTED) { - // Codes_SOCKET_TRANSPORT_LINUX_11_076: [ If successful socket_transport_accept shall return the allocated SOCKET_TRANSPORT of type SOCKET_DATA. ] - result->type = SOCKET_CLIENT; - result->socket = accepted_socket; - sm_open_end(result->sm, true); + // Codes_SOCKET_TRANSPORT_LINUX_11_076: [ If successful socket_transport_accept shall assign accepted_socket to be the allocated incoming SOCKET_TRANSPORT and return SOCKET_ACCEPT_OK. ] + accept_result->type = SOCKET_CLIENT; + accept_result->socket = accepted_socket; + sm_open_end(accept_result->sm, true); sm_exec_end(socket_transport->sm); + result = SOCKET_ACCEPT_OK; + *accepting_socket = accept_result; goto all_ok; } else { LogError("sm_open_begin failed with %" PRI_MU_ENUM " in accept, closing incoming socket.", MU_ENUM_VALUE(SM_RESULT, open_result)); } - sm_destroy(result->sm); + sm_destroy(accept_result->sm); } - // Codes_SOCKET_TRANSPORT_LINUX_11_077: [ If any failure is encountered, socket_transport_accept shall fail and return NULL. ] - free(result); - result = NULL; + // Codes_SOCKET_TRANSPORT_LINUX_11_077: [ If any failure is encountered, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] + free(accept_result); + result = SOCKET_ACCEPT_ERROR; } } close(accepted_socket); @@ -678,7 +692,7 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t sm_exec_end(socket_transport->sm); } } - result = NULL; + result = SOCKET_ACCEPT_ERROR; } all_ok: return result; diff --git a/linux/tests/socket_transport_linux_ut/socket_transport_linux_ut.c b/linux/tests/socket_transport_linux_ut/socket_transport_linux_ut.c index 2c97dbf..3982df3 100644 --- a/linux/tests/socket_transport_linux_ut/socket_transport_linux_ut.c +++ b/linux/tests/socket_transport_linux_ut/socket_transport_linux_ut.c @@ -60,6 +60,8 @@ TEST_DEFINE_ENUM_TYPE(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) IMPLEMENT_UMOCK_C_ENUM_TYPE(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) IMPLEMENT_UMOCK_C_ENUM_TYPE(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES); +TEST_DEFINE_ENUM_TYPE(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) +IMPLEMENT_UMOCK_C_ENUM_TYPE(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES); MU_DEFINE_ENUM_STRINGS(SM_RESULT, SM_RESULT_VALUES); IMPLEMENT_UMOCK_C_ENUM_TYPE(SM_RESULT, SM_RESULT_VALUES); @@ -1317,22 +1319,23 @@ TEST_FUNCTION(socket_transport_listen_sm_open_not_granted_fail) // socket_transport_accept -// Tests_SOCKET_TRANSPORT_LINUX_11_069: [ If socket_transport is NULL, socket_transport_accept shall fail and return NULL. ] +// Tests_SOCKET_TRANSPORT_LINUX_11_069: [ If socket_transport is NULL, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_socket_transport_NULL_fail) { //arrange //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(NULL); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(NULL, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup } -// Tests_SOCKET_TRANSPORT_LINUX_11_070: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return NULL. ] +// Tests_SOCKET_TRANSPORT_LINUX_11_070: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_invalid_type_fail) { //arrange @@ -1341,10 +1344,11 @@ TEST_FUNCTION(socket_transport_accept_invalid_type_fail) umock_c_reset_all_calls(); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1352,7 +1356,7 @@ TEST_FUNCTION(socket_transport_accept_invalid_type_fail) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_LINUX_11_072: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return NULL. ] +// Tests_SOCKET_TRANSPORT_LINUX_11_072: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_not_listening_succeed) { //arrange @@ -1363,10 +1367,69 @@ TEST_FUNCTION(socket_transport_accept_not_listening_succeed) STRICT_EXPECTED_CALL(sm_exec_begin(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + //cleanup + socket_transport_disconnect(socket_handle); + socket_transport_destroy(socket_handle); +} + +// Tests_SOCKET_TRANSPORT_LINUX_11_084: [ If errno is EAGAIN or EWOULDBLOCK, socket_transport_accept shall return SOCKET_ACCEPT_NO_CONNECTION. ] +TEST_FUNCTION(socket_transport_accept_accept_returns_EAGAIN) +{ + //arrange + SOCKET_TRANSPORT_HANDLE socket_handle = socket_transport_create_server(); + ASSERT_IS_NOT_NULL(socket_handle); + ASSERT_ARE_EQUAL(int, 0, socket_transport_listen(socket_handle, TEST_PORT)); + umock_c_reset_all_calls(); + + STRICT_EXPECTED_CALL(sm_exec_begin(IGNORED_ARG)); + STRICT_EXPECTED_CALL(accept(IGNORED_ARG, IGNORED_ARG, IGNORED_ARG)) + .SetReturn(INVALID_SOCKET); + STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); + + errno = EAGAIN; + + //act + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); + + //assert + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_NO_CONNECTION, accept_result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + //cleanup + socket_transport_disconnect(socket_handle); + socket_transport_destroy(socket_handle); +} + +// Tests_SOCKET_TRANSPORT_LINUX_11_084: [ If errno is EAGAIN or EWOULDBLOCK, socket_transport_accept shall return SOCKET_ACCEPT_NO_CONNECTION. ] +TEST_FUNCTION(socket_transport_accept_accept_returns_EWOULDBLOCK) +{ + //arrange + SOCKET_TRANSPORT_HANDLE socket_handle = socket_transport_create_server(); + ASSERT_IS_NOT_NULL(socket_handle); + ASSERT_ARE_EQUAL(int, 0, socket_transport_listen(socket_handle, TEST_PORT)); + umock_c_reset_all_calls(); + + STRICT_EXPECTED_CALL(sm_exec_begin(IGNORED_ARG)); + STRICT_EXPECTED_CALL(accept(IGNORED_ARG, IGNORED_ARG, IGNORED_ARG)) + .SetReturn(INVALID_SOCKET); + STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); + + errno = EWOULDBLOCK; + + //act + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); + + //assert + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_NO_CONNECTION, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1378,7 +1441,7 @@ TEST_FUNCTION(socket_transport_accept_not_listening_succeed) // Tests_SOCKET_TRANSPORT_LINUX_11_073: [ socket_transport_accept shall call accept to accept the incoming socket connection. ] // Tests_SOCKET_TRANSPORT_LINUX_11_074: [ socket_transport_accept shall set the incoming socket to non-blocking. ] // Tests_SOCKET_TRANSPORT_LINUX_11_075: [ socket_transport_accept shall allocate a SOCKET_TRANSPORT for the incoming connection and call sm_create and sm_open on the connection. ] -// Tests_SOCKET_TRANSPORT_LINUX_11_076: [ If successful socket_transport_accept shall return the allocated SOCKET_TRANSPORT of type SOCKET_DATA. ] +// Tests_SOCKET_TRANSPORT_LINUX_11_076: [ If successful socket_transport_accept shall assign accepted_socket to be the allocated incoming SOCKET_TRANSPORT and return SOCKET_ACCEPT_OK. ] TEST_FUNCTION(socket_transport_accept_succeed) { //arrange @@ -1397,9 +1460,11 @@ TEST_FUNCTION(socket_transport_accept_succeed) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_OK, accept_result); ASSERT_IS_NOT_NULL(accept_socket_handle); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); @@ -1410,7 +1475,7 @@ TEST_FUNCTION(socket_transport_accept_succeed) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_LINUX_11_077: [ If any failure is encountered, socket_transport_accept shall fail and return NULL. ] +// Tests_SOCKET_TRANSPORT_LINUX_11_077: [ If any failure is encountered, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_fail) { //arrange @@ -1438,10 +1503,11 @@ TEST_FUNCTION(socket_transport_accept_fail) umock_c_negative_tests_fail_call(index); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); } } diff --git a/win32/devdoc/socket_transport_win32_requirements.md b/win32/devdoc/socket_transport_win32_requirements.md index 8efe237..1e40eee 100644 --- a/win32/devdoc/socket_transport_win32_requirements.md +++ b/win32/devdoc/socket_transport_win32_requirements.md @@ -30,6 +30,13 @@ MU_DEFINE_ENUM(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) MU_DEFINE_ENUM(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) +#define SOCKET_ACCEPT_RESULT_VALUES \ + SOCKET_ACCEPT_OK, \ + SOCKET_ACCEPT_ERROR, \ + SOCKET_ACCEPT_NO_CONNECTION + +MU_DEFINE_ENUM(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) + #define SOCKET_TYPE_VALUES \ SOCKET_CLIENT, \ SOCKET_BINDING @@ -50,7 +57,7 @@ MOCKABLE_FUNCTION(, int, socket_transport_connect, SOCKET_TRANSPORT_HANDLE, sock MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socket_transport, uint16_t, port); MOCKABLE_FUNCTION(, void, socket_transport_disconnect, SOCKET_TRANSPORT_HANDLE, socket_transport); -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); MOCKABLE_FUNCTION(, SOCKET_SEND_RESULT, socket_transport_send, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_sent, uint32_t, flags, void*, data); MOCKABLE_FUNCTION(, SOCKET_RECEIVE_RESULT, socket_transport_receive, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_BUFFER*, payload, uint32_t, buffer_count, uint32_t*, bytes_recv, uint32_t, flags, void*, data); @@ -270,36 +277,38 @@ MOCKABLE_FUNCTION(, int, socket_transport_listen, SOCKET_TRANSPORT_HANDLE, socke ### socket_transport_accept ```c -MOCKABLE_FUNCTION(, SOCKET_TRANSPORT_HANDLE, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport); +MOCKABLE_FUNCTION(, SOCKET_ACCEPT_RESULT, socket_transport_accept, SOCKET_TRANSPORT_HANDLE, socket_transport, SOCKET_TRANSPORT_HANDLE*, accepted_socket); ``` `socket_transport_accept` accepts the incoming connections. -**SOCKET_TRANSPORT_WIN32_09_067: [** If `socket_transport` is `NULL`, `socket_transport_accept` shall fail and return a non-zero value. **]** +**SOCKET_TRANSPORT_WIN32_09_067: [** If `socket_transport` is `NULL`, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** -**SOCKET_TRANSPORT_WIN32_09_068: [** If the transport type is not `SOCKET_BINDING`, `socket_transport_accept` shall fail and return a non-zero value. **]** +**SOCKET_TRANSPORT_WIN32_09_068: [** If the transport type is not `SOCKET_BINDING`, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_WIN32_09_069: [** `socket_transport_accept` shall call `sm_exec_begin`. **]** -**SOCKET_TRANSPORT_WIN32_09_070: [** If `sm_exec_begin` does not return `SM_EXEC_GRANTED`, `socket_transport_accept` shall fail and return `SOCKET_SEND_ERROR`. **]** +**SOCKET_TRANSPORT_WIN32_09_070: [** If `sm_exec_begin` does not return `SM_EXEC_GRANTED`, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_WIN32_09_071: [** `socket_transport_accept` shall call `select` determine if the socket is ready to be read passing a timeout of 10 milliseconds. **]** +**SOCKET_TRANSPORT_WIN32_09_091: [** If `select` returns zero, socket_transport_accept shall set accepted_socket to `NULL` and return `SOCKET_ACCEPT_NO_CONNECTION`. **]** + **SOCKET_TRANSPORT_WIN32_09_072: [** `socket_transport_accept` shall call `accept` to accept the incoming socket connection. **]** -**SOCKET_TRANSPORT_WIN32_09_073: [** If `accept` returns an INVALID_SOCKET, `socket_transport_accept` shall fail and return `Null`. **]** +**SOCKET_TRANSPORT_WIN32_09_073: [** If `accept` returns an INVALID_SOCKET, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_WIN32_09_074: [** `socket_transport_accept` shall allocate a `SOCKET_TRANSPORT` for the incoming connection and call `sm_create` and `sm_open` on the connection. **]** -**SOCKET_TRANSPORT_WIN32_09_084: [** If `malloc` fails, `socket_transport_accept` shall fail and return `NULL`. **]** +**SOCKET_TRANSPORT_WIN32_09_084: [** If `malloc` fails, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** -**SOCKET_TRANSPORT_WIN32_09_085: [** If `sm_create` fails, `socket_transport_accept` shall close the incoming socket, fail, and return `NULL`. **]** +**SOCKET_TRANSPORT_WIN32_09_085: [** If `sm_create` fails, `socket_transport_accept` shall close the incoming socket, fail, and return `SOCKET_ACCEPT_ERROR`. **]** -**SOCKET_TRANSPORT_WIN32_09_086: [** If `sm_open_begin` fails, `socket_transport_accept` shall close the incoming socket, fail, and return `NULL` **]** +**SOCKET_TRANSPORT_WIN32_09_086: [** If `sm_open_begin` fails, `socket_transport_accept` shall close the incoming socket, fail, and return `SOCKET_ACCEPT_ERROR` **]** -**SOCKET_TRANSPORT_WIN32_09_075: [** If successful `socket_transport_accept` shall return the allocated `SOCKET_TRANSPORT`. **]** +**SOCKET_TRANSPORT_WIN32_09_075: [** If successful `socket_transport_accept` shall return `SOCKET_ACCEPT_OK`. **]** -**SOCKET_TRANSPORT_WIN32_09_076: [** If any failure is encountered, `socket_transport_accept` shall fail and return `NULL`. **]** +**SOCKET_TRANSPORT_WIN32_09_076: [** If any failure is encountered, `socket_transport_accept` shall fail and return `SOCKET_ACCEPT_ERROR`. **]** **SOCKET_TRANSPORT_WIN32_09_077: [** `socket_transport_accept` shall call `sm_exec_end`. **]** diff --git a/win32/src/socket_transport_win32.c b/win32/src/socket_transport_win32.c index 634b6f2..8d8c638 100644 --- a/win32/src/socket_transport_win32.c +++ b/win32/src/socket_transport_win32.c @@ -36,6 +36,7 @@ MU_DEFINE_ENUM_STRINGS(SOCKET_IO_TYPE, SOCKET_IO_TYPE_VALUES) MU_DEFINE_ENUM_STRINGS(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) MU_DEFINE_ENUM_STRINGS(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) +MU_DEFINE_ENUM_STRINGS(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) MU_DEFINE_ENUM_STRINGS(SOCKET_TYPE, SOCKET_TYPE_VALUES) typedef struct SOCKET_TRANSPORT_TAG @@ -588,42 +589,42 @@ all_ok: return result; } -SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_transport) +SOCKET_ACCEPT_RESULT socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_transport, SOCKET_TRANSPORT_HANDLE* accepted_socket) { - SOCKET_TRANSPORT* result; + SOCKET_TRANSPORT* accept_result; + SOCKET_ACCEPT_RESULT result; - // Codes_SOCKET_TRANSPORT_WIN32_09_067: [ If socket_transport is NULL, socket_transport_accept shall fail and return a non-zero value. ] + // Codes_SOCKET_TRANSPORT_WIN32_09_067: [ If socket_transport is NULL, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] if (socket_transport == NULL) { LogError("Invalid arguments: SOCKET_TRANSPORT_HANDLE socket_transport: %p", socket_transport); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { - // Codes_SOCKET_TRANSPORT_WIN32_09_068: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return a non-zero value. ] + // Codes_SOCKET_TRANSPORT_WIN32_09_068: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] if (socket_transport->type != SOCKET_BINDING) { LogError("Invalid socket type for this API expected: SOCKET_BINDING, actual: %" PRI_MU_ENUM, MU_ENUM_VALUE(SOCKET_TYPE, socket_transport->type)); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { // Codes_SOCKET_TRANSPORT_WIN32_09_069: [ socket_transport_accept shall call sm_exec_begin. ] SM_RESULT sm_result = sm_exec_begin(socket_transport->sm); - // Codes_SOCKET_TRANSPORT_WIN32_09_070: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return SOCKET_SEND_ERROR. ] + // Codes_SOCKET_TRANSPORT_WIN32_09_070: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] if (sm_result != SM_EXEC_GRANTED) { LogError("sm_exec_begin failed : %" PRI_MU_ENUM, MU_ENUM_VALUE(SM_RESULT, sm_result)); - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { fd_set read_fds; int select_result; struct timeval timeout; - bool is_error = false; read_fds.fd_array[0] = socket_transport->socket; read_fds.fd_count = 1; @@ -635,8 +636,7 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t if (select_result == SOCKET_ERROR) { LogLastError("Error waiting for socket connections %", select_result); - is_error = true; - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else if (select_result > 0) { @@ -644,17 +644,16 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t socklen_t client_len = sizeof(cli_addr); // Codes_SOCKET_TRANSPORT_WIN32_09_072: [ socket_transport_accept shall call accept to accept the incoming socket connection. ] - SOCKET accepted_socket = accept(socket_transport->socket, (struct sockaddr*)&cli_addr, &client_len); + SOCKET accepting_socket = accept(socket_transport->socket, (struct sockaddr*)&cli_addr, &client_len); - // Codes_SOCKET_TRANSPORT_WIN32_09_073: [ If accept returns an INVALID_SOCKET, socket_transport_accept shall fail and return Null. ] - if (accepted_socket == INVALID_SOCKET) + // Codes_SOCKET_TRANSPORT_WIN32_09_073: [ If accept returns an INVALID_SOCKET, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] + if (accepting_socket == INVALID_SOCKET) { if (WSAGetLastError() != WSAEWOULDBLOCK) { LogLastError("Error in accepting socket %" PRI_SOCKET "", accepted_socket); - is_error = true; } - result = NULL; + result = SOCKET_ACCEPT_ERROR; } else { @@ -663,51 +662,58 @@ SOCKET_TRANSPORT_HANDLE socket_transport_accept(SOCKET_TRANSPORT_HANDLE socket_t (void)inet_ntop(AF_INET, (const void*)&cli_addr.sin_addr, hostname_addr, sizeof(hostname_addr)); // Create the socket handle - // Codes_SOCKET_TRANSPORT_WIN32_09_084: [ If malloc fails, socket_transport_accept shall fail and return NULL. ] - result = malloc(sizeof(SOCKET_TRANSPORT)); - if (result == NULL) + // Codes_SOCKET_TRANSPORT_WIN32_09_084: [ If malloc fails, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] + accept_result = malloc(sizeof(SOCKET_TRANSPORT)); + if (accept_result == NULL) { LogError("failure allocating SOCKET_TRANSPORT: %zu", sizeof(SOCKET_TRANSPORT)); + result = SOCKET_ACCEPT_ERROR; } else { - // Codes_SOCKET_TRANSPORT_WIN32_09_085: [ If sm_create fails, socket_transport_accept shall close the incoming socket, fail, and return NULL. ] - result->sm = sm_create("Socket_transport_win32"); - if (result->sm == NULL) + // Codes_SOCKET_TRANSPORT_WIN32_09_085: [ If sm_create fails, socket_transport_accept shall close the incoming socket, fail, and return SOCKET_ACCEPT_ERROR. ] + accept_result->sm = sm_create("Socket_transport_win32"); + if (accept_result->sm == NULL) { LogError("Failed calling sm_create in accept, closing incoming socket."); - closesocket(accepted_socket); - free(result); - result = NULL; + closesocket(accepting_socket); + free(accept_result); + result = SOCKET_ACCEPT_ERROR; } else { - // Codes_SOCKET_TRANSPORT_WIN32_09_086: [ If sm_open_begin fails, socket_transport_accept shall close the incoming socket, fail, and return NULL ] - SM_RESULT open_result = sm_open_begin(result->sm); + // Codes_SOCKET_TRANSPORT_WIN32_09_086: [ If sm_open_begin fails, socket_transport_accept shall close the incoming socket, fail, and return SOCKET_ACCEPT_ERROR ] + SM_RESULT open_result = sm_open_begin(accept_result->sm); if (open_result == SM_EXEC_GRANTED) { - result->type = SOCKET_CLIENT; - result->socket = accepted_socket; - sm_open_end(result->sm, true); + accept_result->type = SOCKET_CLIENT; + accept_result->socket = accepting_socket; + sm_open_end(accept_result->sm, true); + *accepted_socket = accept_result; + result = SOCKET_ACCEPT_OK; } else { LogError("sm_open_begin failed with %" PRI_MU_ENUM " in accept, closing incoming socket.", MU_ENUM_VALUE(SM_RESULT, open_result)); - closesocket(accepted_socket); - sm_destroy(result->sm); - free(result); - result = NULL; + closesocket(accepting_socket); + sm_destroy(accept_result->sm); + free(accept_result); + result = SOCKET_ACCEPT_ERROR; } } } } } + // Codes_SOCKET_TRANSPORT_WIN32_09_091: [ If select returns zero, socket_transport_accept shall set accepted_socket to NULL and return SOCKET_ACCEPT_NO_CONNECTION. ] + else if (select_result == 0) + { + result = SOCKET_ACCEPT_NO_CONNECTION; + } else { - // Codes_SOCKET_TRANSPORT_WIN32_09_076: [ If any failure is encountered, socket_transport_accept shall fail and return NULL. ] + // Codes_SOCKET_TRANSPORT_WIN32_09_076: [ If any failure is encountered, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] LogLastError("Failure accepting socket connection"); - is_error = true; - result = NULL; + result = SOCKET_ACCEPT_ERROR; } // Codes_SOCKET_TRANSPORT_WIN32_09_077: [ socket_transport_accept shall call sm_exec_end. ] sm_exec_end(socket_transport->sm); diff --git a/win32/tests/socket_transport_win32_ut/socket_transport_win32_ut.c b/win32/tests/socket_transport_win32_ut/socket_transport_win32_ut.c index d5dbcac..a598b1b 100644 --- a/win32/tests/socket_transport_win32_ut/socket_transport_win32_ut.c +++ b/win32/tests/socket_transport_win32_ut/socket_transport_win32_ut.c @@ -60,6 +60,8 @@ TEST_DEFINE_ENUM_TYPE(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES) IMPLEMENT_UMOCK_C_ENUM_TYPE(SOCKET_SEND_RESULT, SOCKET_SEND_RESULT_VALUES); TEST_DEFINE_ENUM_TYPE(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES) IMPLEMENT_UMOCK_C_ENUM_TYPE(SOCKET_RECEIVE_RESULT, SOCKET_RECEIVE_RESULT_VALUES); +TEST_DEFINE_ENUM_TYPE(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES) +IMPLEMENT_UMOCK_C_ENUM_TYPE(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_RESULT_VALUES); MU_DEFINE_ENUM_STRINGS(UMOCK_C_ERROR_CODE, UMOCK_C_ERROR_CODE_VALUES) @@ -1455,7 +1457,7 @@ TEST_FUNCTION(socket_transport_listen_fail) // Tests_SOCKET_TRANSPORT_WIN32_09_071: [ socket_transport_accept shall call select determine if the socket is ready to be read passing a timeout of 10 milliseconds. ] // Tests_SOCKET_TRANSPORT_WIN32_09_072: [ socket_transport_accept shall call accept to accept the incoming socket connection. ] // Tests_SOCKET_TRANSPORT_WIN32_09_074: [ socket_transport_accept shall allocate a SOCKET_TRANSPORT for the incoming connection and call sm_create and sm_open on the connection. ] -// Tests_SOCKET_TRANSPORT_WIN32_09_075: [ If successful socket_transport_accept shall return the allocated SOCKET_TRANSPORT. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_075: [ If successful socket_transport_accept shall return SOCKET_ACCEPT_OK. ] TEST_FUNCTION(socket_transport_accept_succeed) { //arrange @@ -1475,9 +1477,11 @@ TEST_FUNCTION(socket_transport_accept_succeed) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_OK, accept_result); ASSERT_IS_NOT_NULL(accept_socket_handle); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); @@ -1488,7 +1492,7 @@ TEST_FUNCTION(socket_transport_accept_succeed) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_067: [ If socket_transport is NULL, socket_transport_accept shall fail and return a non-zero value. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_067: [ If socket_transport is NULL, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_null_input_fail) { //arrange @@ -1496,14 +1500,15 @@ TEST_FUNCTION(socket_transport_accept_null_input_fail) umock_c_negative_tests_snapshot(); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(NULL); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(NULL, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); } -// Tests_SOCKET_TRANSPORT_WIN32_09_068: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return a non-zero value. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_068: [ If the transport type is not SOCKET_BINDING, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_sockettransport_type_fail) { //arrange @@ -1513,17 +1518,18 @@ TEST_FUNCTION(socket_transport_accept_sockettransport_type_fail) umock_c_negative_tests_snapshot(); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_070: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return SOCKET_SEND_ERROR. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_070: [ If sm_exec_begin does not return SM_EXEC_GRANTED, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_smexecbegin_fail) { //arrange @@ -1536,10 +1542,11 @@ TEST_FUNCTION(socket_transport_accept_smexecbegin_fail) .SetReturn(SM_EXEC_REFUSED); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1562,10 +1569,11 @@ TEST_FUNCTION(socket_transport_accept_select_fail) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1573,7 +1581,35 @@ TEST_FUNCTION(socket_transport_accept_select_fail) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_073: [ If accept returns an INVALID_SOCKET, socket_transport_accept shall fail and return Null. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_091: [ If select returns zero, socket_transport_accept shall set accepted_socket to NULL and return SOCKET_ACCEPT_NO_CONNECTION. ] +TEST_FUNCTION(socket_transport_accept_select_returns_zero) +{ + //arrange + SOCKET_TRANSPORT_HANDLE socket_handle = socket_transport_create_server(); + ASSERT_IS_NOT_NULL(socket_handle); + ASSERT_ARE_EQUAL(int, 0, socket_transport_listen(socket_handle, TEST_PORT)); + umock_c_reset_all_calls(); + umock_c_negative_tests_snapshot(); + + STRICT_EXPECTED_CALL(sm_exec_begin(IGNORED_ARG)); + STRICT_EXPECTED_CALL(select(IGNORED_ARG, IGNORED_ARG, IGNORED_ARG, IGNORED_ARG, IGNORED_ARG)) + .SetReturn(0); + STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); + + //act + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); + + //assert + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_NO_CONNECTION, accept_result); + ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); + + //cleanup + socket_transport_disconnect(socket_handle); + socket_transport_destroy(socket_handle); +} + +// Tests_SOCKET_TRANSPORT_WIN32_09_073: [ If accept returns an INVALID_SOCKET, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_accept_fail) { //arrange @@ -1592,10 +1628,11 @@ TEST_FUNCTION(socket_transport_accept_accept_fail) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1603,7 +1640,7 @@ TEST_FUNCTION(socket_transport_accept_accept_fail) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_084: [ If malloc fails, socket_transport_accept shall fail and return NULL. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_084: [ If malloc fails, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_malloc_fail) { //arrange @@ -1625,10 +1662,11 @@ TEST_FUNCTION(socket_transport_accept_malloc_fail) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1636,7 +1674,7 @@ TEST_FUNCTION(socket_transport_accept_malloc_fail) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_085: [ If sm_create fails, socket_transport_accept shall close the incoming socket, fail, and return NULL. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_085: [ If sm_create fails, socket_transport_accept shall close the incoming socket, fail, and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_sm_create_fail) { //arrange @@ -1657,10 +1695,11 @@ TEST_FUNCTION(socket_transport_accept_sm_create_fail) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1668,7 +1707,7 @@ TEST_FUNCTION(socket_transport_accept_sm_create_fail) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_086: [ If sm_open_begin fails, socket_transport_accept shall close the incoming socket, fail, and return NULL ] +// Tests_SOCKET_TRANSPORT_WIN32_09_086: [ If sm_open_begin fails, socket_transport_accept shall close the incoming socket, fail, and return SOCKET_ACCEPT_ERROR ] TEST_FUNCTION(socket_transport_accept_sm_open_begin_fail) { //arrange @@ -1691,10 +1730,11 @@ TEST_FUNCTION(socket_transport_accept_sm_open_begin_fail) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup @@ -1702,7 +1742,7 @@ TEST_FUNCTION(socket_transport_accept_sm_open_begin_fail) socket_transport_destroy(socket_handle); } -// Tests_SOCKET_TRANSPORT_WIN32_09_076: [ If any failure is encountered, socket_transport_accept shall fail and return NULL. ] +// Tests_SOCKET_TRANSPORT_WIN32_09_076: [ If any failure is encountered, socket_transport_accept shall fail and return SOCKET_ACCEPT_ERROR. ] TEST_FUNCTION(socket_transport_accept_fail) { //arrange @@ -1717,10 +1757,11 @@ TEST_FUNCTION(socket_transport_accept_fail) STRICT_EXPECTED_CALL(sm_exec_end(IGNORED_ARG)); //act - SOCKET_TRANSPORT_HANDLE accept_socket_handle = socket_transport_accept(socket_handle); + SOCKET_TRANSPORT_HANDLE accept_socket_handle; + SOCKET_ACCEPT_RESULT accept_result = socket_transport_accept(socket_handle, &accept_socket_handle); //assert - ASSERT_IS_NULL(accept_socket_handle); + ASSERT_ARE_EQUAL(SOCKET_ACCEPT_RESULT, SOCKET_ACCEPT_ERROR, accept_result); ASSERT_ARE_EQUAL(char_ptr, umock_c_get_expected_calls(), umock_c_get_actual_calls()); //cleanup