Skip to content

Commit

Permalink
state change handler expansion
Browse files Browse the repository at this point in the history
  • Loading branch information
sbSteveK committed Sep 24, 2024
1 parent 6984b79 commit c8e2a5e
Showing 1 changed file with 97 additions and 87 deletions.
184 changes: 97 additions & 87 deletions source/darwin/nw_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit c8e2a5e

Please sign in to comment.