Skip to content

Commit

Permalink
cancel timeout args in cleanup&unsupported network_interface_name
Browse files Browse the repository at this point in the history
  • Loading branch information
xiazhvera committed Oct 7, 2024
1 parent 1f78abc commit 7e3b4c0
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 26 deletions.
5 changes: 3 additions & 2 deletions include/aws/io/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ struct aws_socket_options {
* This property is used to bind the socket to a particular network interface by name, such as eth0 and ens32.
* If this is empty, the socket will not be bound to any interface and will use OS defaults. If the provided name
* is invalid, `aws_socket_init()` will error out with AWS_IO_SOCKET_INVALID_OPTIONS. This option is only
* supported on Linux, macOS, and platforms that have either SO_BINDTODEVICE or IP_BOUND_IF. It is not supported on
* Windows. `AWS_ERROR_PLATFORM_NOT_SUPPORTED` will be raised on unsupported platforms.
* supported on Linux, macOS(bsd socket), and platforms that have either SO_BINDTODEVICE or IP_BOUND_IF. It is not
* supported on Windows and Apple Network Framework. `AWS_ERROR_PLATFORM_NOT_SUPPORTED` will be raised on
* unsupported platforms.
*/
char network_interface_name[AWS_NETWORK_INTERFACE_NAME_MAX];
};
Expand Down
69 changes: 46 additions & 23 deletions source/darwin/nw_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,6 @@ static void s_socket_impl_destroy(void *sock_ptr) {
nw_socket->nw_listener = NULL;
}

if (nw_socket->timeout_args) {
aws_mem_release(nw_socket->allocator, nw_socket->timeout_args);
}

aws_mem_release(nw_socket->allocator, nw_socket);
nw_socket = NULL;
}
Expand All @@ -317,6 +313,26 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons
AWS_ASSERT(options);
AWS_ZERO_STRUCT(*socket);

// Network Interface is not supported with Apple Network Framework yet
size_t network_interface_length = 0;
if (aws_secure_strlen(options->network_interface_name, AWS_NETWORK_INTERFACE_NAME_MAX, &network_interface_length)) {
AWS_LOGF_ERROR(
AWS_LS_IO_SOCKET,
"id=%p fd=%d: network_interface_name max length must be %d length and NULL terminated",
(void *)socket,
socket->io_handle.data.fd,
AWS_NETWORK_INTERFACE_NAME_MAX);
return aws_raise_error(AWS_IO_SOCKET_INVALID_OPTIONS);
}
if (network_interface_length != 0) {
AWS_LOGF_ERROR(
AWS_LS_IO_SOCKET,
"id=%p fd=%d: network_interface_name is not supported on this platform.",
(void *)socket,
socket->io_handle.data.fd);
return aws_raise_error(AWS_ERROR_PLATFORM_NOT_SUPPORTED);
}

struct nw_socket *nw_socket = aws_mem_calloc(alloc, 1, sizeof(struct nw_socket));
nw_socket->allocator = alloc;

Expand Down Expand Up @@ -350,31 +366,33 @@ static void s_handle_socket_timeout(struct aws_task *task, void *args, aws_task_
(void)task;
(void)status;

if (status == AWS_TASK_STATUS_CANCELED) {
// We will clean up the task and args on socket destory.
return;
}
struct nw_socket_timeout_args *timeout_args = args;

AWS_LOGF_TRACE(AWS_LS_IO_SOCKET, "task_id=%p: timeout task triggered, evaluating timeouts.", (void *)task);
/* successful connection will have nulled out timeout_args->socket */
if (timeout_args->socket) {
AWS_LOGF_ERROR(
AWS_LS_IO_SOCKET,
"id=%p handle=%p: timed out, shutting down.",
(void *)timeout_args->socket,
timeout_args->socket->io_handle.data.handle);
if (status != AWS_TASK_STATUS_CANCELED) {

timeout_args->socket->state = TIMEDOUT;
int error_code = AWS_IO_SOCKET_TIMEOUT;
AWS_LOGF_TRACE(AWS_LS_IO_SOCKET, "task_id=%p: timeout task triggered, evaluating timeouts.", (void *)task);
/* successful connection will have nulled out timeout_args->socket */
if (timeout_args->socket) {
AWS_LOGF_ERROR(
AWS_LS_IO_SOCKET,
"id=%p handle=%p: timed out, shutting down.",
(void *)timeout_args->socket,
timeout_args->socket->io_handle.data.handle);

struct nw_socket *socket_impl = timeout_args->socket->impl;
timeout_args->socket->state = TIMEDOUT;
int error_code = AWS_IO_SOCKET_TIMEOUT;

aws_raise_error(error_code);
struct aws_socket *socket = timeout_args->socket;
aws_socket_close(socket);
socket_impl->on_connection_result_fn(socket, error_code, socket_impl->connect_accept_user_data);
struct nw_socket *socket_impl = timeout_args->socket->impl;

aws_raise_error(error_code);
struct aws_socket *socket = timeout_args->socket;
aws_socket_close(socket);
socket_impl->on_connection_result_fn(socket, error_code, socket_impl->connect_accept_user_data);
}
}

aws_mem_release(timeout_args->allocator, timeout_args);
timeout_args = NULL;
}

static void s_process_readable_task(struct aws_task *task, void *arg, enum aws_task_status status) {
Expand Down Expand Up @@ -1059,6 +1077,11 @@ static int s_socket_close_fn(struct aws_socket *socket) {
struct nw_socket *nw_socket = socket->impl;
AWS_LOGF_DEBUG(AWS_LS_IO_SOCKET, "id=%p handle=%p: closing", (void *)socket, socket->io_handle.data.handle);

if (nw_socket->timeout_args) {
// if the timeout args is not triggered, cancel it
s_schedule_cancel_task(socket, &nw_socket->timeout_args->task);
}

/* disable the handlers. We already know it closed and don't need pointless use-after-free event/async hell*/
if (nw_socket->is_listener) {
nw_listener_set_state_changed_handler(socket->io_handle.data.handle, NULL);
Expand Down
5 changes: 4 additions & 1 deletion tests/socket_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ static int s_test_socket_with_bind_to_invalid_interface(struct aws_allocator *al
options.domain = AWS_SOCKET_IPV4;
strncpy(options.network_interface_name, "invalid", AWS_NETWORK_INTERFACE_NAME_MAX);
struct aws_socket outgoing;
#if defined(AWS_OS_APPLE) || defined(AWS_OS_LINUX)
#if defined(AWS_OS_APPLE) && !s_use_dispatch_queue || defined(AWS_OS_LINUX)
ASSERT_ERROR(AWS_IO_SOCKET_INVALID_OPTIONS, aws_socket_init(&outgoing, allocator, &options));
#else
ASSERT_ERROR(AWS_ERROR_PLATFORM_NOT_SUPPORTED, aws_socket_init(&outgoing, allocator, &options));
Expand Down Expand Up @@ -1133,6 +1133,9 @@ static int s_test_wrong_thread_read_write_fails(struct aws_allocator *allocator,
aws_socket_clean_up(&socket);
aws_event_loop_destroy(event_loop);

// DEBUG WIP, sleep to wait for reference release
aws_thread_current_sleep(1000000000);

return 0;
}

Expand Down

0 comments on commit 7e3b4c0

Please sign in to comment.