int aws_client_bootstrap_new_socket_channel()

in source/channel_bootstrap.c [725:877]


int aws_client_bootstrap_new_socket_channel(struct aws_socket_channel_bootstrap_options *options) {

    struct aws_client_bootstrap *bootstrap = options->bootstrap;
    AWS_FATAL_ASSERT(options->setup_callback);
    AWS_FATAL_ASSERT(options->shutdown_callback);
    AWS_FATAL_ASSERT(bootstrap);

    const struct aws_socket_options *socket_options = options->socket_options;
    AWS_FATAL_ASSERT(socket_options != NULL);

    const struct aws_tls_connection_options *tls_options = options->tls_options;

    AWS_FATAL_ASSERT(tls_options == NULL || socket_options->type == AWS_SOCKET_STREAM);
    aws_io_fatal_assert_library_initialized();

    if (options->requested_event_loop != NULL) {
        /* If we're asking for a specific event loop, verify it belongs to the bootstrap's event loop group */
        if (!(s_does_event_loop_belong_to_event_loop_group(
                options->requested_event_loop, bootstrap->event_loop_group))) {
            return aws_raise_error(AWS_ERROR_IO_PINNED_EVENT_LOOP_MISMATCH);
        }
    }

    struct client_connection_args *client_connection_args =
        aws_mem_calloc(bootstrap->allocator, 1, sizeof(struct client_connection_args));

    if (!client_connection_args) {
        return AWS_OP_ERR;
    }

    const char *host_name = options->host_name;
    uint16_t port = options->port;

    AWS_LOGF_TRACE(
        AWS_LS_IO_CHANNEL_BOOTSTRAP,
        "id=%p: attempting to initialize a new client channel to %s:%d",
        (void *)bootstrap,
        host_name,
        (int)port);

    aws_ref_count_init(
        &client_connection_args->ref_count,
        client_connection_args,
        (aws_simple_completion_callback *)s_client_connection_args_destroy);
    client_connection_args->user_data = options->user_data;
    client_connection_args->bootstrap = aws_client_bootstrap_acquire(bootstrap);
    client_connection_args->creation_callback = options->creation_callback;
    client_connection_args->setup_callback = options->setup_callback;
    client_connection_args->shutdown_callback = options->shutdown_callback;
    client_connection_args->outgoing_options = *socket_options;
    client_connection_args->outgoing_port = port;
    client_connection_args->enable_read_back_pressure = options->enable_read_back_pressure;
    client_connection_args->requested_event_loop = options->requested_event_loop;

    if (tls_options) {
        if (aws_tls_connection_options_copy(&client_connection_args->channel_data.tls_options, tls_options)) {
            goto error;
        }
        client_connection_args->channel_data.use_tls = true;

        client_connection_args->channel_data.on_protocol_negotiated = bootstrap->on_protocol_negotiated;
        client_connection_args->channel_data.tls_user_data = tls_options->user_data;

        /* in order to honor any callbacks a user may have installed on their tls_connection_options,
         * we need to wrap them if they were set.*/
        if (bootstrap->on_protocol_negotiated) {
            client_connection_args->channel_data.tls_options.advertise_alpn_message = true;
        }

        if (tls_options->on_data_read) {
            client_connection_args->channel_data.user_on_data_read = tls_options->on_data_read;
            client_connection_args->channel_data.tls_options.on_data_read = s_tls_client_on_data_read;
        }

        if (tls_options->on_error) {
            client_connection_args->channel_data.user_on_error = tls_options->on_error;
            client_connection_args->channel_data.tls_options.on_error = s_tls_client_on_error;
        }

        if (tls_options->on_negotiation_result) {
            client_connection_args->channel_data.user_on_negotiation_result = tls_options->on_negotiation_result;
        }

        client_connection_args->channel_data.tls_options.on_negotiation_result = s_tls_client_on_negotiation_result;
        client_connection_args->channel_data.tls_options.user_data = client_connection_args;
    }

    if (s_aws_socket_domain_uses_dns(socket_options->domain)) {
        client_connection_args->host_name = aws_string_new_from_c_str(bootstrap->allocator, host_name);

        if (!client_connection_args->host_name) {
            goto error;
        }

        if (aws_host_resolver_resolve_host(
                bootstrap->host_resolver,
                client_connection_args->host_name,
                s_on_host_resolved,
                &bootstrap->host_resolver_config,
                client_connection_args)) {
            goto error;
        }
    } else {
        /* ensure that the pipe/domain socket name will fit in the endpoint address */
        const size_t host_name_len = strlen(host_name);
        if (host_name_len >= AWS_ADDRESS_MAX_LEN) {
            aws_raise_error(AWS_IO_SOCKET_INVALID_ADDRESS);
            goto error;
        }

        struct aws_socket_endpoint endpoint;
        AWS_ZERO_STRUCT(endpoint);
        memcpy(endpoint.address, host_name, host_name_len);
        if (socket_options->domain == AWS_SOCKET_VSOCK) {
            endpoint.port = port;
        } else {
            endpoint.port = 0;
        }

        struct aws_socket *outgoing_socket = aws_mem_acquire(bootstrap->allocator, sizeof(struct aws_socket));

        if (!outgoing_socket) {
            goto error;
        }

        if (aws_socket_init(outgoing_socket, bootstrap->allocator, socket_options)) {
            aws_mem_release(bootstrap->allocator, outgoing_socket);
            goto error;
        }

        client_connection_args->addresses_count = 1;

        struct aws_event_loop *connect_loop = s_get_connection_event_loop(client_connection_args);

        s_client_connection_args_acquire(client_connection_args);
        if (aws_socket_connect(
                outgoing_socket, &endpoint, connect_loop, s_on_client_connection_established, client_connection_args)) {
            aws_socket_clean_up(outgoing_socket);
            aws_mem_release(client_connection_args->bootstrap->allocator, outgoing_socket);
            s_client_connection_args_release(client_connection_args);
            goto error;
        }
    }

    return AWS_OP_SUCCESS;

error:
    if (client_connection_args) {
        /* tls opt will also be freed when we clean up the connection arg */
        s_client_connection_args_release(client_connection_args);
    }
    return AWS_OP_ERR;
}