diff --git a/include/aws/http/server.h b/include/aws/http/server.h index c6aaf5a6..03893355 100644 --- a/include/aws/http/server.h +++ b/include/aws/http/server.h @@ -195,6 +195,12 @@ int aws_http_connection_configure_server( AWS_HTTP_API bool aws_http_connection_is_server(const struct aws_http_connection *connection); +/** + * Returns the local listener endpoint of the HTTP server. Only valid as long as the server remains valid. + */ +AWS_HTTP_API +const struct aws_socket_endpoint *aws_http_server_get_listener_endpoint(const struct aws_http_server *server); + AWS_EXTERN_C_END AWS_POP_SANE_WARNING_LEVEL diff --git a/source/connection.c b/source/connection.c index 6d53ab4b..a53aebe1 100644 --- a/source/connection.c +++ b/source/connection.c @@ -762,6 +762,12 @@ void aws_http_server_release(struct aws_http_server *server) { * clean up will be called from eventloop */ } +const struct aws_socket_endpoint *aws_http_server_get_listener_endpoint(const struct aws_http_server *server) { + AWS_FATAL_ASSERT(server); + + return &server->socket->local_endpoint; +} + /* At this point, the channel bootstrapper has established a connection to the server and set up a channel. * Now we need to create the aws_http_connection and insert it into the channel as a channel-handler. */ static void s_client_bootstrap_on_channel_setup( diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 06dc389f..879badab 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -498,6 +498,7 @@ add_test_case(h2_client_manual_data_write_no_data) add_test_case(h2_client_manual_data_write_connection_close) add_test_case(server_new_destroy) +add_test_case(server_new_destroy_tcp) add_test_case(connection_setup_shutdown) add_test_case(connection_setup_shutdown_tls) add_test_case(connection_setup_shutdown_proxy_setting_on_ev_not_found) diff --git a/tests/test_connection.c b/tests/test_connection.c index 50f575a7..71c0c36e 100644 --- a/tests/test_connection.c +++ b/tests/test_connection.c @@ -44,6 +44,7 @@ struct tester_options { char *client_alpn_list; bool no_connection; /* don't connect server to client */ bool pin_event_loop; + bool use_tcp; /* otherwise uses domain sockets */ }; /* Singleton used by tests in this file */ @@ -336,22 +337,23 @@ static int s_tester_init(struct tester *tester, const struct tester_options *opt struct aws_socket_options socket_options = { .type = AWS_SOCKET_STREAM, - .domain = AWS_SOCKET_LOCAL, + .domain = options->use_tcp ? AWS_SOCKET_IPV4 : AWS_SOCKET_LOCAL, .connect_timeout_ms = (uint32_t)aws_timestamp_convert(TESTER_TIMEOUT_SEC, AWS_TIMESTAMP_SECS, AWS_TIMESTAMP_MILLIS, NULL), }; tester->socket_options = socket_options; - /* Generate random address for endpoint */ - struct aws_uuid uuid; - ASSERT_SUCCESS(aws_uuid_init(&uuid)); - char uuid_str[AWS_UUID_STR_LEN]; - struct aws_byte_buf uuid_buf = aws_byte_buf_from_empty_array(uuid_str, sizeof(uuid_str)); - ASSERT_SUCCESS(aws_uuid_to_str(&uuid, &uuid_buf)); + struct aws_socket_endpoint endpoint; AWS_ZERO_STRUCT(endpoint); - snprintf(endpoint.address, sizeof(endpoint.address), LOCAL_SOCK_TEST_FORMAT, uuid_str); + if (options->use_tcp) { + snprintf(endpoint.address, sizeof(endpoint.address), "127.0.0.1"); + } else { + aws_socket_endpoint_init_local_address_for_test(&endpoint); + } + tester->endpoint = endpoint; + /* Create server (listening socket) */ struct aws_http_server_options server_options = AWS_HTTP_SERVER_OPTIONS_INIT; server_options.allocator = tester->alloc; @@ -370,6 +372,14 @@ static int s_tester_init(struct tester *tester, const struct tester_options *opt tester->server = aws_http_server_new(&server_options); ASSERT_NOT_NULL(tester->server); + /* + * localhost server binds to any port, so let's get the final listener endpoint whether or not we're making + * connections to it. + */ + if (options->use_tcp) { + tester->endpoint = *aws_http_server_get_listener_endpoint(tester->server); + } + /* If test doesn't need a connection, we're done setting up. */ if (options->no_connection) { return AWS_OP_SUCCESS; @@ -448,6 +458,20 @@ static int s_test_server_new_destroy(struct aws_allocator *allocator, void *ctx) } AWS_TEST_CASE(server_new_destroy, s_test_server_new_destroy); +static int s_test_server_new_destroy_tcp(struct aws_allocator *allocator, void *ctx) { + (void)ctx; + struct tester_options options = {.alloc = allocator, .no_connection = true, .use_tcp = true}; + struct tester tester; + ASSERT_SUCCESS(s_tester_init(&tester, &options)); + + const struct aws_socket_endpoint *listener_endpoint = aws_http_server_get_listener_endpoint(tester.server); + ASSERT_TRUE(listener_endpoint->port > 0); + + ASSERT_SUCCESS(s_tester_clean_up(&tester)); + return AWS_OP_SUCCESS; +} +AWS_TEST_CASE(server_new_destroy_tcp, s_test_server_new_destroy_tcp); + void release_all_client_connections(struct tester *tester) { for (int i = 0; i < tester->client_connection_num; i++) { aws_http_connection_release(tester->client_connections[i]);