in src/connection.c [1851:1938]
ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection)
{
ENDPOINT_HANDLE result;
/* Codes_S_R_S_CONNECTION_01_113: [If connection, on_endpoint_frame_received or on_connection_state_changed is NULL, connection_create_endpoint shall fail and return NULL.] */
/* Codes_S_R_S_CONNECTION_01_193: [The context argument shall be allowed to be NULL.] */
if (connection == NULL)
{
LogError("NULL connection");
result = NULL;
}
else
{
/* Codes_S_R_S_CONNECTION_01_115: [If no more endpoints can be created due to all channels being used, connection_create_endpoint shall fail and return NULL.] */
if (connection->endpoint_count >= connection->channel_max)
{
result = NULL;
}
else
{
uint32_t i = 0;
/* Codes_S_R_S_CONNECTION_01_128: [The lowest number outgoing channel shall be associated with the newly created endpoint.] */
for (i = 0; i < connection->endpoint_count; i++)
{
if (connection->endpoints[i]->outgoing_channel > i)
{
/* found a gap in the sorted endpoint array */
break;
}
}
/* Codes_S_R_S_CONNECTION_01_127: [On success, connection_create_endpoint shall return a non-NULL handle to the newly created endpoint.] */
result = (ENDPOINT_HANDLE)calloc(1, sizeof(ENDPOINT_INSTANCE));
/* Codes_S_R_S_CONNECTION_01_196: [If memory cannot be allocated for the new endpoint, connection_create_endpoint shall fail and return NULL.] */
if (result == NULL)
{
LogError("Cannot allocate memory for endpoint");
}
else
{
ENDPOINT_HANDLE* new_endpoints;
result->on_endpoint_frame_received = NULL;
result->on_connection_state_changed = NULL;
result->callback_context = NULL;
result->outgoing_channel = (uint16_t)i;
result->connection = connection;
/* Codes_S_R_S_CONNECTION_01_197: [The newly created endpoint shall be added to the endpoints list, so that it can be tracked.] */
size_t realloc_size = safe_add_size_t((size_t)connection->endpoint_count, 1);
realloc_size = safe_multiply_size_t(realloc_size, sizeof(ENDPOINT_HANDLE));
if (realloc_size == SIZE_MAX ||
(new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, realloc_size)) == NULL)
{
/* Tests_S_R_S_CONNECTION_01_198: [If adding the endpoint to the endpoints list tracked by the connection fails, connection_create_endpoint shall fail and return NULL.] */
LogError("Cannot reallocate memory for connection endpoints, size:%zu", realloc_size);
free(result);
result = NULL;
}
else
{
connection->endpoints = new_endpoints;
if (i < connection->endpoint_count)
{
size_t memmove_size = safe_multiply_size_t(safe_subtract_size_t(connection->endpoint_count, i), sizeof(ENDPOINT_INSTANCE*));
if (memmove_size != SIZE_MAX)
{
(void)memmove(&connection->endpoints[i + 1], &connection->endpoints[i], memmove_size);
}
else
{
LogError("Cannot memmove endpoints, size:%zu", memmove_size);
}
}
connection->endpoints[i] = result;
connection->endpoint_count++;
/* Codes_S_R_S_CONNECTION_01_112: [connection_create_endpoint shall create a new endpoint that can be used by a session.] */
}
}
}
}
return result;
}