static CONCRETE_IO_HANDLE header_detect_io_create()

in src/header_detect_io.c [463:620]


static CONCRETE_IO_HANDLE header_detect_io_create(void* io_create_parameters)
{
    HEADER_DETECT_IO_INSTANCE* result;

    if (io_create_parameters == NULL)
    {
        /* Codes_SRS_HEADER_DETECT_IO_01_003: [ If `io_create_parameters` is NULL, `header_detect_io_create` shall fail and return NULL. ]*/
        LogError("NULL io_create_parameters");
        result = NULL;
    }
    else
    {
        /* Codes_SRS_HEADER_DETECT_IO_01_004: [ `io_create_parameters` shall be used as `HEADER_DETECT_IO_CONFIG*`. ]*/
        HEADER_DETECT_IO_CONFIG* header_detect_io_config = (HEADER_DETECT_IO_CONFIG*)io_create_parameters;

        /* Codes_SRS_HEADER_DETECT_IO_01_005: [ If the member `header_detect_entry_count` of `HEADER_DETECT_IO_CONFIG` is 0 then `header_detect_io_create` shall fail and return NULL. ]*/
        if ((header_detect_io_config->header_detect_entry_count == 0) ||
            /* Codes_SRS_HEADER_DETECT_IO_01_006: [ If the member `header_detect_entries` is NULL then `header_detect_io_create` shall fail and return NULL. ]*/
            (header_detect_io_config->header_detect_entries == NULL) ||
            /* Codes_SRS_HEADER_DETECT_IO_01_007: [ If the member `underlying_io` is NULL then `header_detect_io_create` shall fail and return NULL. ]*/
            (header_detect_io_config->underlying_io == NULL))
        {
            LogError("Bad create parameters: header_detect_entry_count = %lu, header_detect_entries = %p, underlying_io = %p",
                (unsigned long)header_detect_io_config->header_detect_entry_count,
                header_detect_io_config->header_detect_entries,
                header_detect_io_config->underlying_io);
            result = NULL;
        }
        else
        {
            size_t i;
            bool null_io_found = false;

            for (i = 0; i < header_detect_io_config->header_detect_entry_count; i++)
            {
                /* Codes_SRS_HEADER_DETECT_IO_01_052: [ The `io` member in the in each of the `header_detect_entries` shall be allowed to be NULL. ]*/
                if (header_detect_io_config->header_detect_entries[i].header.header_bytes == NULL)
                {
                    LogError("header detect entry %u is invalid", (unsigned int)i);
                    break;
                }

                if (header_detect_io_config->header_detect_entries[i].io_interface_description == NULL)
                {
                    null_io_found = true;
                }
            }

            if (i < header_detect_io_config->header_detect_entry_count)
            {
                result = NULL;
            }
            else if (!null_io_found)
            {
                /* Codes_SRS_HEADER_DETECT_IO_01_054: [ At least one entry in `header_detect_entries` shall have IO set to NULL, otherwise `header_detect_io_create` shall fail and return NULL. ]*/
                LogError("No default header found");
                result = NULL;
            }
            else
            {
                /* Codes_SRS_HEADER_DETECT_IO_01_001: [ `header_detect_io_create` shall create a new header detect IO instance and on success it shall return a non-NULL handle to the newly created instance. ] */
                result = (HEADER_DETECT_IO_INSTANCE*)calloc(1, sizeof(HEADER_DETECT_IO_INSTANCE));
                if (result == NULL)
                {
                    /* Codes_SRS_HEADER_DETECT_IO_01_002: [ If allocating memory for the header detect IO instance fails, `header_detect_io_create` shall fail and return NULL. ]*/
                    LogError("Cannot allocate memory for header detect IO");
                }
                else
                {
                    /* Codes_SRS_HEADER_DETECT_IO_01_009: [ The `header_detect_entries` array shall be copied so that it can be later used when detecting which header was received. ]*/
                    size_t calloc_size = safe_multiply_size_t(header_detect_io_config->header_detect_entry_count, sizeof(INTERNAL_HEADER_DETECT_ENTRY));
                    if (calloc_size == SIZE_MAX ||
                        (result->header_detect_entries = (INTERNAL_HEADER_DETECT_ENTRY*)calloc(1, calloc_size)) == NULL)
                    {
                        LogError("Could not allocate header_detect_entries, size:%zu", calloc_size);
                        free(result);
                        result = NULL;
                    }
                    else
                    {
                        result->header_detect_entry_count = header_detect_io_config->header_detect_entry_count;

                        /* Codes_SRS_HEADER_DETECT_IO_01_009: [ The `header_detect_entries` array shall be copied so that it can be later used when detecting which header was received. ]*/
                        for (i = 0; i < header_detect_io_config->header_detect_entry_count; i++)
                        {
                            result->header_detect_entries[i].header_size = header_detect_io_config->header_detect_entries[i].header.header_size;
                            result->header_detect_entries[i].header_bytes = (unsigned char*)malloc(result->header_detect_entries[i].header_size);
                            if (result->header_detect_entries[i].header_bytes == NULL)
                            {
                                /* Codes_SRS_HEADER_DETECT_IO_01_010: [ If allocating memory for the `header_detect_entries` or its constituents fails then `header_detect_io_create` shall fail and return NULL. ]*/
                                break;
                            }
                            else
                            {
                                /* Codes_SRS_HEADER_DETECT_IO_01_014: [ For each entry in `header_detect_entries` the `header` field shall also be copied. ]*/
                                (void)memcpy(result->header_detect_entries[i].header_bytes, header_detect_io_config->header_detect_entries[i].header.header_bytes, result->header_detect_entries[i].header_size);
                                result->header_detect_entries[i].io_interface_description = header_detect_io_config->header_detect_entries[i].io_interface_description;
                            }
                        }

                        if (i < header_detect_io_config->header_detect_entry_count)
                        {
                            size_t j;

                            LogError("Failed copying header detect configuration");
                            for (j = 0; j < i; j++)
                            {
                                free(result->header_detect_entries[j].header_bytes);
                            }

                            free(result->header_detect_entries);
                            free(result);
                            result = NULL;
                        }
                        else
                        {
                            /* Codes_SRS_HEADER_DETECT_IO_01_060: [ `header_detect_io_create` shall create a singly linked list by calling `singlylinkedlist_create` where the chained detected IOs shall be stored. ]*/
                            result->chained_io_list = singlylinkedlist_create();
                            if (result->chained_io_list == NULL)
                            {
                                /* Codes_SRS_HEADER_DETECT_IO_01_065: [ If `singlylinkedlist_create` fails then `header_detect_io_create` shall fail and return NULL. ]*/
                                LogError("Failed copying header detect configuration");
                                for (i = 0; i < result->header_detect_entry_count; i++)
                                {
                                    free(result->header_detect_entries[i].header_bytes);
                                    result->header_detect_entries[i].header_bytes = NULL;
                                }

                                free(result->header_detect_entries);
                                free(result);
                                result = NULL;
                            }
                            else
                            {
                                result->underlying_io = header_detect_io_config->underlying_io;
                                result->on_io_open_complete = NULL;
                                result->on_io_close_complete = NULL;
                                result->on_io_error = NULL;
                                result->on_bytes_received = NULL;
                                result->on_io_open_complete_context = NULL;
                                result->on_io_close_complete_context = NULL;
                                result->on_io_error_context = NULL;
                                result->on_bytes_received_context = NULL;

                                /* Codes_SRS_HEADER_DETECT_IO_01_070: [ If no detected IO was created then `header_detect_io_close_async` shall close the `underlying_io` passed in `header_detect_io_create`. ]*/
                                result->last_io = &result->underlying_io;

                                result->io_state = IO_STATE_NOT_OPEN;
                            }
                        }
                    }
                }
            }
        }
    }

    return result;
}