From c8e2a5eb26514668c045717bf0f220a6e39c7db2 Mon Sep 17 00:00:00 2001 From: Steve Kim Date: Tue, 24 Sep 2024 10:25:26 -0700 Subject: [PATCH] state change handler expansion --- source/darwin/nw_socket.c | 184 ++++++++++++++++++++------------------ 1 file changed, 97 insertions(+), 87 deletions(-) diff --git a/source/darwin/nw_socket.c b/source/darwin/nw_socket.c index 9429c130b..5f502f59b 100644 --- a/source/darwin/nw_socket.c +++ b/source/darwin/nw_socket.c @@ -477,93 +477,103 @@ static int s_socket_connect_fn( /* set a handler for socket state changes. This is where we find out if the connection timed out, was successful, * was disconnected etc .... */ - nw_connection_set_state_changed_handler(handle, ^(nw_connection_state_t state, nw_error_t error) { - AWS_LOGF_DEBUG( - AWS_LS_IO_SOCKET, - "id=%p handle=%p: connection state changed hanlder, state: %d", - (void *)socket, - handle, - state); - /* we're connected! */ - if (state == nw_connection_state_ready) { - AWS_LOGF_INFO(AWS_LS_IO_SOCKET, "id=%p handle=%p: connection success", (void *)socket, handle); - nw_socket->socket_open = true; - nw_path_t path = nw_connection_copy_current_path(handle); - nw_endpoint_t local_endpoint = nw_path_copy_effective_local_endpoint(path); - nw_release(path); - const char *hostname = nw_endpoint_get_hostname(local_endpoint); - uint16_t port = nw_endpoint_get_port(local_endpoint); - - size_t hostname_len = strlen(hostname); - size_t buffer_size = AWS_ARRAY_SIZE(socket->local_endpoint.address); - size_t to_copy = aws_min_size(hostname_len, buffer_size); - memcpy(socket->local_endpoint.address, hostname, to_copy); - socket->local_endpoint.port = port; - nw_release(local_endpoint); - - // Cancel the connection timeout task - aws_event_loop_cancel_task(event_loop, &nw_socket->timeout_args->task); - - AWS_LOGF_DEBUG( - AWS_LS_IO_SOCKET, - "id=%p handle=%p: local endpoint %s:%d", - (void *)socket, - handle, - socket->local_endpoint.address, - port); - - socket->state = CONNECTED_WRITE | CONNECTED_READ; - aws_ref_count_acquire(&nw_socket->ref_count); - on_connection_result(socket, AWS_OP_SUCCESS, user_data); - aws_ref_count_release(&nw_socket->ref_count); - nw_socket->setup_run = true; - } else if (error) { - /* any error, including if closed remotely in error */ - int error_code = nw_error_get_error_code(error); - AWS_LOGF_ERROR( - AWS_LS_IO_SOCKET, - "id=%p handle=%p: connection error %d", - (void *)socket, - socket->io_handle.data.handle, - error_code); - // Cancel the connection timeout task - aws_event_loop_cancel_task(event_loop, &nw_socket->timeout_args->task); - /* we don't let this thing do DNS or TLS. Everything had better be a posix error. */ - AWS_ASSERT(nw_error_get_error_domain(error) == nw_error_domain_posix); - error_code = s_determine_socket_error(error_code); - nw_socket->last_error = error_code; - aws_raise_error(error_code); - socket->state = ERROR; - aws_ref_count_acquire(&nw_socket->ref_count); - if (!nw_socket->setup_run) { - on_connection_result(socket, error_code, user_data); - nw_socket->setup_run = true; - } else if (socket->readable_fn) { - socket->readable_fn(socket, nw_socket->last_error, socket->readable_user_data); - } - - aws_ref_count_release(&nw_socket->ref_count); - } else if (state == nw_connection_state_cancelled || state == nw_connection_state_failed) { - /* this should only hit when the socket was closed by not us. Note, - * we uninstall this handler right before calling close on the socket so this shouldn't - * get hit unless it was triggered remotely */ - // Cancel the connection timeout task - aws_event_loop_cancel_task(event_loop, &nw_socket->timeout_args->task); - AWS_LOGF_DEBUG( - AWS_LS_IO_SOCKET, "id=%p handle=%p: socket closed", (void *)socket, socket->io_handle.data.handle); - socket->state = CLOSED; - aws_ref_count_acquire(&nw_socket->ref_count); - aws_raise_error(AWS_IO_SOCKET_CLOSED); - if (!nw_socket->setup_run) { - on_connection_result(socket, AWS_IO_SOCKET_CLOSED, user_data); - nw_socket->setup_run = true; - } else if (socket->readable_fn) { - socket->readable_fn(socket, AWS_IO_SOCKET_CLOSED, socket->readable_user_data); - } - aws_ref_count_release(&nw_socket->ref_count); - } - - }); + nw_connection_set_state_changed_handler( + socket->io_handle.data.handle, ^(nw_connection_state_t state, nw_error_t error) { + /* we're connected! */ + if (state == nw_connection_state_ready) { + AWS_LOGF_INFO( + AWS_LS_IO_SOCKET, + "id=%p handle=%p: connection success", + (void *)socket, + socket->io_handle.data.handle); + nw_socket->socket_open = true; + nw_path_t path = nw_connection_copy_current_path(socket->io_handle.data.handle); + nw_endpoint_t local_endpoint = nw_path_copy_effective_local_endpoint(path); + nw_release(path); + const char *hostname = nw_endpoint_get_hostname(local_endpoint); + uint16_t port = nw_endpoint_get_port(local_endpoint); + + size_t hostname_len = strlen(hostname); + size_t buffer_size = AWS_ARRAY_SIZE(socket->local_endpoint.address); + size_t to_copy = aws_min_size(hostname_len, buffer_size); + memcpy(socket->local_endpoint.address, hostname, to_copy); + socket->local_endpoint.port = port; + nw_release(local_endpoint); + + AWS_LOGF_DEBUG( + AWS_LS_IO_SOCKET, + "id=%p handle=%p: local endpoint %s:%d", + (void *)socket, + socket->io_handle.data.handle, + socket->local_endpoint.address, + port); + // Cancel the connection timeout task + aws_event_loop_cancel_task(event_loop, &nw_socket->timeout_args->task); + socket->state = CONNECTED_WRITE | CONNECTED_READ; + nw_socket->setup_run = true; + aws_ref_count_acquire(&nw_socket->ref_count); + on_connection_result(socket, AWS_OP_SUCCESS, user_data); + aws_ref_count_release(&nw_socket->ref_count); + } else if (error) { + /* any error, including if closed remotely in error */ + int error_code = nw_error_get_error_code(error); + AWS_LOGF_ERROR( + AWS_LS_IO_SOCKET, + "id=%p handle=%p: connection error %d", + (void *)socket, + socket->io_handle.data.handle, + error_code); + + // Cancel the connection timeout task + aws_event_loop_cancel_task(event_loop, &nw_socket->timeout_args->task); + + /* we don't let this thing do DNS or TLS. Everything had better be a posix error. */ + // AWS_ASSERT(nw_error_get_error_domain(error) == nw_error_domain_posix); + // DEBUG WIP we do in fact allow this to do TLS + error_code = s_determine_socket_error(error_code); + nw_socket->last_error = error_code; + aws_raise_error(error_code); + socket->state = ERROR; + aws_ref_count_acquire(&nw_socket->ref_count); + if (!nw_socket->setup_run) { + on_connection_result(socket, error_code, user_data); + nw_socket->setup_run = true; + } else if (socket->readable_fn) { + socket->readable_fn(socket, nw_socket->last_error, socket->readable_user_data); + } + aws_ref_count_release(&nw_socket->ref_count); + } else if (state == nw_connection_state_cancelled || state == nw_connection_state_failed) { + /* this should only hit when the socket was closed by not us. Note, + * we uninstall this handler right before calling close on the socket so this shouldn't + * get hit unless it was triggered remotely */ + // Cancel the connection timeout task + aws_event_loop_cancel_task(event_loop, &nw_socket->timeout_args->task); + AWS_LOGF_DEBUG( + AWS_LS_IO_SOCKET, + "id=%p handle=%p: socket closed remotely.", + (void *)socket, socket->io_handle.data.handle); + socket->state = CLOSED; + aws_ref_count_acquire(&nw_socket->ref_count); + aws_raise_error(AWS_IO_SOCKET_CLOSED); + if (!nw_socket->setup_run) { + on_connection_result(socket, AWS_IO_SOCKET_CLOSED, user_data); + nw_socket->setup_run = true; + } else if (socket->readable_fn) { + socket->readable_fn(socket, AWS_IO_SOCKET_CLOSED, socket->readable_user_data); + } + aws_ref_count_release(&nw_socket->ref_count); + } else if (state == nw_connection_state_waiting) { + AWS_LOGF_DEBUG( + AWS_LS_IO_SOCKET, + "id=%p handle=%p: socket connection is waiting for a usable network before re-attempting.", + (void *)socket, socket->io_handle.data.handle); + } else if (state == nw_connection_state_preparing) { + AWS_LOGF_DEBUG( + AWS_LS_IO_SOCKET, + "id=%p handle=%p: socket connection is in the process of establishing.", + (void *)socket, socket->io_handle.data.handle); + } + }); nw_connection_start(socket->io_handle.data.handle); nw_retain(socket->io_handle.data.handle);