LINK_ENDPOINT_HANDLE session_create_link_endpoint()

in src/session.c [1096:1181]


LINK_ENDPOINT_HANDLE session_create_link_endpoint(SESSION_HANDLE session, const char* name)
{
    LINK_ENDPOINT_INSTANCE* result;

    /* Codes_S_R_S_SESSION_01_044: [If session, name or frame_received_callback is NULL, session_create_link_endpoint shall fail and return NULL.] */
    if ((session == NULL) ||
        (name == NULL))
    {
        result = NULL;
    }
    else
    {
        /* Codes_S_R_S_SESSION_01_043: [session_create_link_endpoint shall create a link endpoint associated with a given session and return a non-NULL handle to it.] */
        SESSION_INSTANCE* session_instance = (SESSION_INSTANCE*)session;

        result = (LINK_ENDPOINT_INSTANCE*)calloc(1, sizeof(LINK_ENDPOINT_INSTANCE));
        /* Codes_S_R_S_SESSION_01_045: [If allocating memory for the link endpoint fails, session_create_link_endpoint shall fail and return NULL.] */
        if (result != NULL)
        {
            /* Codes_S_R_S_SESSION_01_046: [An unused handle shall be assigned to the link endpoint.] */
            handle selected_handle = 0;
            size_t i;
            size_t name_length;

            for (i = 0; i < session_instance->link_endpoint_count; i++)
            {
                if (session_instance->link_endpoints[i]->output_handle > selected_handle)
                {
                    break;
                }

                selected_handle++;
            }

            result->on_session_state_changed = NULL;
            result->on_session_flow_on = NULL;
            result->frame_received_callback = NULL;
            result->callback_context = NULL;
            result->output_handle = selected_handle;
            result->input_handle = 0xFFFFFFFF;
            result->link_endpoint_state = LINK_ENDPOINT_STATE_NOT_ATTACHED;
            name_length = strlen(name);
            result->name = (char*)malloc(name_length + 1);
            result->on_link_endpoint_destroyed_callback = NULL;
            result->on_link_endpoint_destroyed_context = NULL;
            if (result->name == NULL)
            {
                /* Codes_S_R_S_SESSION_01_045: [If allocating memory for the link endpoint fails, session_create_link_endpoint shall fail and return NULL.] */
                free(result);
                result = NULL;
            }
            else
            {
                LINK_ENDPOINT_INSTANCE** new_link_endpoints;
                (void)memcpy(result->name, name, name_length + 1);
                result->session = session;

                size_t realloc_size = safe_add_size_t((size_t)session_instance->link_endpoint_count, 1);
                realloc_size = safe_multiply_size_t(realloc_size, sizeof(LINK_ENDPOINT_INSTANCE));
                if (realloc_size == SIZE_MAX ||
                    (new_link_endpoints = (LINK_ENDPOINT_INSTANCE**)realloc(session_instance->link_endpoints, realloc_size)) == NULL)
                {
                    /* Codes_S_R_S_SESSION_01_045: [If allocating memory for the link endpoint fails, session_create_link_endpoint shall fail and return NULL.] */
                    LogError("Cannot realloc new_link_endpoints, size:%zu", realloc_size);
                    free(result->name);
                    free(result);
                    result = NULL;
                }
                else
                {
                    session_instance->link_endpoints = new_link_endpoints;

                    if (session_instance->link_endpoint_count - selected_handle > 0)
                    {
                        (void)memmove(&session_instance->link_endpoints[selected_handle + 1], &session_instance->link_endpoints[selected_handle], (session_instance->link_endpoint_count - selected_handle) * sizeof(LINK_ENDPOINT_INSTANCE*));
                    }

                    session_instance->link_endpoints[selected_handle] = result;
                    session_instance->link_endpoint_count++;
                }
            }
        }
    }

    return result;
}