int amqp_frame_codec_encode_frame()

in src/amqp_frame_codec.c [221:336]


int amqp_frame_codec_encode_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, AMQP_VALUE performative, const PAYLOAD* payloads, size_t payload_count, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context)
{
    int result;

    /* Codes_SRS_AMQP_FRAME_CODEC_01_024: [If frame_codec, performative or on_bytes_encoded is NULL, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
    if ((amqp_frame_codec == NULL) ||
        (performative == NULL) ||
        (on_bytes_encoded == NULL))
    {
        LogError("Bad arguments: amqp_frame_codec = %p, performative = %p, on_bytes_encoded = %p",
            amqp_frame_codec, performative, on_bytes_encoded);
        result = MU_FAILURE;
    }
    else
    {
        AMQP_VALUE descriptor;
        uint64_t performative_ulong;
        size_t encoded_size;

        if ((descriptor = amqpvalue_get_inplace_descriptor(performative)) == NULL)
        {
            /* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
            LogError("Getting the descriptor failed");
            result = MU_FAILURE;
        }
        else if (amqpvalue_get_ulong(descriptor, &performative_ulong) != 0)
        {
            /* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
            LogError("Getting the descriptor ulong failed");
            result = MU_FAILURE;
        }
        /* Codes_SRS_AMQP_FRAME_CODEC_01_008: [The performative MUST be one of those defined in section 2.7 and is encoded as a described type in the AMQP type system.] */
        else if ((performative_ulong < AMQP_OPEN) ||
            (performative_ulong > AMQP_CLOSE))
        {
            /* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
            LogError("Bad arguments: amqp_frame_codec = %p, performative = %p, on_bytes_encoded = %p",
                amqp_frame_codec, performative, on_bytes_encoded);
            result = MU_FAILURE;
        }
        /* Codes_SRS_AMQP_FRAME_CODEC_01_027: [The encoded size of the performative and its fields shall be obtained by calling amqpvalue_get_encoded_size.] */
        else if (amqpvalue_get_encoded_size(performative, &encoded_size) != 0)
        {
            /* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
            LogError("Getting the encoded size failed");
            result = MU_FAILURE;
        }
        else
        {
            unsigned char* amqp_performative_bytes = (unsigned char*)malloc(encoded_size);
            if (amqp_performative_bytes == NULL)
            {
                LogError("Could not allocate performative bytes");
                result = MU_FAILURE;
            }
            else
            {
                PAYLOAD* new_payloads;
                size_t calloc_size = safe_add_size_t(payload_count, 1);
                calloc_size = safe_multiply_size_t(calloc_size, sizeof(PAYLOAD));
                if (calloc_size == SIZE_MAX ||
                    (new_payloads = (PAYLOAD*)calloc(1, calloc_size)) == NULL)
                {
                    LogError("Could not allocate frame payloads, size:%zu", calloc_size);
                    result = MU_FAILURE;
                }
                else
                {
                    /* Codes_SRS_AMQP_FRAME_CODEC_01_070: [The payloads argument for frame_codec_encode_frame shall be made of the payload for the encoded performative and the payloads passed to amqp_frame_codec_encode_frame.] */
                    /* Codes_SRS_AMQP_FRAME_CODEC_01_028: [The encode result for the performative shall be placed in a PAYLOAD structure.] */
                    new_payloads[0].bytes = amqp_performative_bytes;
                    new_payloads[0].length = 0;

                    if (payload_count > 0)
                    {
                        (void)memcpy(new_payloads + 1, payloads, sizeof(PAYLOAD) * payload_count);
                    }

                    if (amqpvalue_encode(performative, encode_bytes, &new_payloads[0]) != 0)
                    {
                        LogError("amqpvalue_encode failed");
                        result = MU_FAILURE;
                    }
                    else
                    {
                        unsigned char channel_bytes[2];

                        channel_bytes[0] = channel >> 8;
                        channel_bytes[1] = channel & 0xFF;

                        /* Codes_SRS_AMQP_FRAME_CODEC_01_005: [Bytes 6 and 7 of an AMQP frame contain the channel number ] */
                        /* Codes_SRS_AMQP_FRAME_CODEC_01_025: [amqp_frame_codec_encode_frame shall encode the frame header by using frame_codec_encode_frame.] */
                        /* Codes_SRS_AMQP_FRAME_CODEC_01_006: [The frame body is defined as a performative followed by an opaque payload.] */
                        if (frame_codec_encode_frame(amqp_frame_codec->frame_codec, FRAME_TYPE_AMQP, new_payloads, payload_count + 1, channel_bytes, sizeof(channel_bytes), on_bytes_encoded, callback_context) != 0)
                        {
                            /* Codes_SRS_AMQP_FRAME_CODEC_01_029: [If any error occurs during encoding, amqp_frame_codec_encode_frame shall fail and return a non-zero value.] */
                            LogError("frame_codec_encode_frame failed");
                            result = MU_FAILURE;
                        }
                        else
                        {
                            /* Codes_SRS_AMQP_FRAME_CODEC_01_022: [amqp_frame_codec_begin_encode_frame shall encode the frame header and AMQP performative in an AMQP frame and on success it shall return 0.] */
                            result = 0;
                        }
                    }

                    free(new_payloads);
                }

                free(amqp_performative_bytes);
            }
        }
    }

    return result;
}