A small memory footprint AMQP implimentation
Dependents: iothub_client_sample_amqp remote_monitoring simplesample_amqp
amqp_frame_codec.c@43:4c1e4e94cdd3, 2018-06-11 (annotated)
- Committer:
- AzureIoTClient
- Date:
- Mon Jun 11 15:39:52 2018 -0700
- Revision:
- 43:4c1e4e94cdd3
- Parent:
- 30:0407b2db334c
- Child:
- 46:01f7ca900e07
1.2.5
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Azure.IoT Build | 0:6ae2f7bca550 | 1 | // Copyright (c) Microsoft. All rights reserved. |
Azure.IoT Build | 0:6ae2f7bca550 | 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
Azure.IoT Build | 0:6ae2f7bca550 | 3 | |
Azure.IoT Build | 0:6ae2f7bca550 | 4 | #include <stdlib.h> |
Azure.IoT Build | 0:6ae2f7bca550 | 5 | #include <stdint.h> |
Azure.IoT Build | 0:6ae2f7bca550 | 6 | #include <stddef.h> |
Azure.IoT Build | 0:6ae2f7bca550 | 7 | #include <string.h> |
AzureIoTClient | 19:000ab4e6a2c1 | 8 | #include "azure_c_shared_utility/optimize_size.h" |
AzureIoTClient | 20:206846c14c80 | 9 | #include "azure_c_shared_utility/gballoc.h" |
AzureIoTClient | 27:d74f1cea23e1 | 10 | #include "azure_c_shared_utility/xlogging.h" |
Azure.IoT Build | 0:6ae2f7bca550 | 11 | #include "azure_uamqp_c/amqp_frame_codec.h" |
Azure.IoT Build | 0:6ae2f7bca550 | 12 | #include "azure_uamqp_c/frame_codec.h" |
Azure.IoT Build | 0:6ae2f7bca550 | 13 | #include "azure_uamqp_c/amqpvalue.h" |
Azure.IoT Build | 0:6ae2f7bca550 | 14 | |
Azure.IoT Build | 0:6ae2f7bca550 | 15 | typedef enum AMQP_FRAME_DECODE_STATE_TAG |
Azure.IoT Build | 0:6ae2f7bca550 | 16 | { |
AzureIoTClient | 28:add19eb7defa | 17 | AMQP_FRAME_DECODE_FRAME, |
AzureIoTClient | 28:add19eb7defa | 18 | AMQP_FRAME_DECODE_ERROR |
Azure.IoT Build | 0:6ae2f7bca550 | 19 | } AMQP_FRAME_DECODE_STATE; |
Azure.IoT Build | 0:6ae2f7bca550 | 20 | |
AzureIoTClient | 43:4c1e4e94cdd3 | 21 | typedef struct AMQP_FRAME_CODEC_TAG |
Azure.IoT Build | 0:6ae2f7bca550 | 22 | { |
AzureIoTClient | 28:add19eb7defa | 23 | FRAME_CODEC_HANDLE frame_codec; |
Azure.IoT Build | 0:6ae2f7bca550 | 24 | |
AzureIoTClient | 28:add19eb7defa | 25 | /* decode */ |
AzureIoTClient | 28:add19eb7defa | 26 | AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback; |
AzureIoTClient | 28:add19eb7defa | 27 | AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback; |
AzureIoTClient | 28:add19eb7defa | 28 | AMQP_FRAME_CODEC_ERROR_CALLBACK error_callback; |
AzureIoTClient | 28:add19eb7defa | 29 | void* callback_context; |
AzureIoTClient | 28:add19eb7defa | 30 | AMQPVALUE_DECODER_HANDLE decoder; |
AzureIoTClient | 28:add19eb7defa | 31 | AMQP_FRAME_DECODE_STATE decode_state; |
AzureIoTClient | 28:add19eb7defa | 32 | AMQP_VALUE decoded_performative; |
AzureIoTClient | 43:4c1e4e94cdd3 | 33 | } AMQP_FRAME_CODEC; |
Azure.IoT Build | 0:6ae2f7bca550 | 34 | |
Azure.IoT Build | 0:6ae2f7bca550 | 35 | static void amqp_value_decoded(void* context, AMQP_VALUE decoded_value) |
Azure.IoT Build | 0:6ae2f7bca550 | 36 | { |
AzureIoTClient | 43:4c1e4e94cdd3 | 37 | AMQP_FRAME_CODEC_HANDLE amqp_frame_codec = (AMQP_FRAME_CODEC_HANDLE)context; |
AzureIoTClient | 28:add19eb7defa | 38 | uint64_t performative_descriptor_ulong; |
AzureIoTClient | 28:add19eb7defa | 39 | AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(decoded_value); |
Azure.IoT Build | 0:6ae2f7bca550 | 40 | |
AzureIoTClient | 28:add19eb7defa | 41 | /* Codes_SRS_AMQP_FRAME_CODEC_01_060: [If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.] */ |
AzureIoTClient | 28:add19eb7defa | 42 | if ((descriptor == NULL) || |
AzureIoTClient | 28:add19eb7defa | 43 | (amqpvalue_get_ulong(descriptor, &performative_descriptor_ulong) != 0) || |
AzureIoTClient | 28:add19eb7defa | 44 | /* Codes_SRS_AMQP_FRAME_CODEC_01_003: [The performative MUST be one of those defined in section 2.7 and is encoded as a described type in the AMQP type system.] */ |
AzureIoTClient | 28:add19eb7defa | 45 | (performative_descriptor_ulong < AMQP_OPEN) || |
AzureIoTClient | 28:add19eb7defa | 46 | (performative_descriptor_ulong > AMQP_CLOSE)) |
AzureIoTClient | 28:add19eb7defa | 47 | { |
AzureIoTClient | 28:add19eb7defa | 48 | /* Codes_SRS_AMQP_FRAME_CODEC_01_060: [If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 49 | amqp_frame_codec->decode_state = AMQP_FRAME_DECODE_ERROR; |
AzureIoTClient | 28:add19eb7defa | 50 | } |
AzureIoTClient | 28:add19eb7defa | 51 | else |
AzureIoTClient | 28:add19eb7defa | 52 | { |
AzureIoTClient | 43:4c1e4e94cdd3 | 53 | amqp_frame_codec->decoded_performative = decoded_value; |
AzureIoTClient | 28:add19eb7defa | 54 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 55 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 56 | |
Azure.IoT Build | 0:6ae2f7bca550 | 57 | static void frame_received(void* context, const unsigned char* type_specific, uint32_t type_specific_size, const unsigned char* frame_body, uint32_t frame_body_size) |
Azure.IoT Build | 0:6ae2f7bca550 | 58 | { |
AzureIoTClient | 43:4c1e4e94cdd3 | 59 | AMQP_FRAME_CODEC_HANDLE amqp_frame_codec = (AMQP_FRAME_CODEC_HANDLE)context; |
AzureIoTClient | 28:add19eb7defa | 60 | uint16_t channel; |
Azure.IoT Build | 0:6ae2f7bca550 | 61 | |
AzureIoTClient | 43:4c1e4e94cdd3 | 62 | switch (amqp_frame_codec->decode_state) |
AzureIoTClient | 28:add19eb7defa | 63 | { |
AzureIoTClient | 28:add19eb7defa | 64 | default: |
AzureIoTClient | 28:add19eb7defa | 65 | /* Codes_SRS_AMQP_FRAME_CODEC_01_050: [All subsequent decoding shall fail and no AMQP frames shall be indicated from that point on to the consumers of amqp_frame_codec.] */ |
AzureIoTClient | 28:add19eb7defa | 66 | case AMQP_FRAME_DECODE_ERROR: |
AzureIoTClient | 28:add19eb7defa | 67 | break; |
Azure.IoT Build | 0:6ae2f7bca550 | 68 | |
AzureIoTClient | 28:add19eb7defa | 69 | case AMQP_FRAME_DECODE_FRAME: |
AzureIoTClient | 28:add19eb7defa | 70 | /* Codes_SRS_AMQP_FRAME_CODEC_01_049: [If not enough type specific bytes are received to decode the channel number, the decoding shall stop with an error.] */ |
AzureIoTClient | 28:add19eb7defa | 71 | if (type_specific_size < 2) |
AzureIoTClient | 28:add19eb7defa | 72 | { |
AzureIoTClient | 43:4c1e4e94cdd3 | 73 | amqp_frame_codec->decode_state = AMQP_FRAME_DECODE_ERROR; |
Azure.IoT Build | 0:6ae2f7bca550 | 74 | |
AzureIoTClient | 28:add19eb7defa | 75 | /* Codes_SRS_AMQP_FRAME_CODEC_01_069: [If any error occurs while decoding a frame, the decoder shall indicate the error by calling the amqp_frame_codec_error_callback and passing to it the callback context argument that was given in amqp_frame_codec_create.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 76 | amqp_frame_codec->error_callback(amqp_frame_codec->callback_context); |
AzureIoTClient | 28:add19eb7defa | 77 | } |
AzureIoTClient | 28:add19eb7defa | 78 | else |
AzureIoTClient | 28:add19eb7defa | 79 | { |
AzureIoTClient | 28:add19eb7defa | 80 | /* Codes_SRS_AMQP_FRAME_CODEC_01_001: [Bytes 6 and 7 of an AMQP frame contain the channel number ] */ |
AzureIoTClient | 28:add19eb7defa | 81 | channel = ((uint16_t)type_specific[0]) << 8; |
AzureIoTClient | 28:add19eb7defa | 82 | channel += type_specific[1]; |
Azure.IoT Build | 0:6ae2f7bca550 | 83 | |
AzureIoTClient | 28:add19eb7defa | 84 | if (frame_body_size == 0) |
AzureIoTClient | 28:add19eb7defa | 85 | { |
AzureIoTClient | 28:add19eb7defa | 86 | /* Codes_SRS_AMQP_FRAME_CODEC_01_048: [When a frame header is received from frame_codec and the frame payload size is 0, empty_frame_received_callback shall be invoked, while passing the channel number as argument.] */ |
AzureIoTClient | 28:add19eb7defa | 87 | /* Codes_SRS_AMQP_FRAME_CODEC_01_007: [An AMQP frame with no body MAY be used to generate artificial traffic as needed to satisfy any negotiated idle timeout interval ] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 88 | amqp_frame_codec->empty_frame_received_callback(amqp_frame_codec->callback_context, channel); |
AzureIoTClient | 28:add19eb7defa | 89 | } |
AzureIoTClient | 28:add19eb7defa | 90 | else |
AzureIoTClient | 28:add19eb7defa | 91 | { |
AzureIoTClient | 28:add19eb7defa | 92 | /* Codes_SRS_AMQP_FRAME_CODEC_01_051: [If the frame payload is greater than 0, amqp_frame_codec shall decode the performative as a described AMQP type.] */ |
AzureIoTClient | 28:add19eb7defa | 93 | /* Codes_SRS_AMQP_FRAME_CODEC_01_002: [The frame body is defined as a performative followed by an opaque payload.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 94 | amqp_frame_codec->decoded_performative = NULL; |
Azure.IoT Build | 0:6ae2f7bca550 | 95 | |
AzureIoTClient | 28:add19eb7defa | 96 | while ((frame_body_size > 0) && |
AzureIoTClient | 43:4c1e4e94cdd3 | 97 | (amqp_frame_codec->decoded_performative == NULL) && |
AzureIoTClient | 43:4c1e4e94cdd3 | 98 | (amqp_frame_codec->decode_state != AMQP_FRAME_DECODE_ERROR)) |
AzureIoTClient | 28:add19eb7defa | 99 | { |
AzureIoTClient | 28:add19eb7defa | 100 | /* Codes_SRS_AMQP_FRAME_CODEC_01_052: [Decoding the performative shall be done by feeding the bytes to the decoder create in amqp_frame_codec_create.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 101 | if (amqpvalue_decode_bytes(amqp_frame_codec->decoder, frame_body, 1) != 0) |
AzureIoTClient | 28:add19eb7defa | 102 | { |
AzureIoTClient | 28:add19eb7defa | 103 | /* Codes_SRS_AMQP_FRAME_CODEC_01_060: [If any error occurs while decoding a frame, the decoder shall switch to an error state where decoding shall not be possible anymore.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 104 | amqp_frame_codec->decode_state = AMQP_FRAME_DECODE_ERROR; |
AzureIoTClient | 28:add19eb7defa | 105 | } |
AzureIoTClient | 28:add19eb7defa | 106 | else |
AzureIoTClient | 28:add19eb7defa | 107 | { |
AzureIoTClient | 28:add19eb7defa | 108 | frame_body_size--; |
AzureIoTClient | 28:add19eb7defa | 109 | frame_body++; |
AzureIoTClient | 28:add19eb7defa | 110 | } |
AzureIoTClient | 28:add19eb7defa | 111 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 112 | |
AzureIoTClient | 43:4c1e4e94cdd3 | 113 | if (amqp_frame_codec->decode_state == AMQP_FRAME_DECODE_ERROR) |
AzureIoTClient | 28:add19eb7defa | 114 | { |
AzureIoTClient | 28:add19eb7defa | 115 | /* Codes_SRS_AMQP_FRAME_CODEC_01_069: [If any error occurs while decoding a frame, the decoder shall indicate the error by calling the amqp_frame_codec_error_callback and passing to it the callback context argument that was given in amqp_frame_codec_create.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 116 | amqp_frame_codec->error_callback(amqp_frame_codec->callback_context); |
AzureIoTClient | 28:add19eb7defa | 117 | } |
AzureIoTClient | 28:add19eb7defa | 118 | else |
AzureIoTClient | 28:add19eb7defa | 119 | { |
AzureIoTClient | 28:add19eb7defa | 120 | /* Codes_SRS_AMQP_FRAME_CODEC_01_004: [The remaining bytes in the frame body form the payload for that frame.] */ |
AzureIoTClient | 28:add19eb7defa | 121 | /* Codes_SRS_AMQP_FRAME_CODEC_01_067: [When the performative is decoded, the rest of the frame_bytes shall not be given to the AMQP decoder, but they shall be buffered so that later they are given to the frame_received callback.] */ |
AzureIoTClient | 28:add19eb7defa | 122 | /* Codes_SRS_AMQP_FRAME_CODEC_01_054: [Once the performative is decoded and all frame payload bytes are received, the callback frame_received_callback shall be called.] */ |
AzureIoTClient | 28:add19eb7defa | 123 | /* Codes_SRS_AMQP_FRAME_CODEC_01_068: [A pointer to all the payload bytes shall also be passed to frame_received_callback.] */ |
AzureIoTClient | 43:4c1e4e94cdd3 | 124 | amqp_frame_codec->frame_received_callback(amqp_frame_codec->callback_context, channel, amqp_frame_codec->decoded_performative, frame_body, frame_body_size); |
AzureIoTClient | 28:add19eb7defa | 125 | } |
AzureIoTClient | 28:add19eb7defa | 126 | } |
AzureIoTClient | 28:add19eb7defa | 127 | } |
AzureIoTClient | 28:add19eb7defa | 128 | break; |
AzureIoTClient | 28:add19eb7defa | 129 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 130 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 131 | |
Azure.IoT Build | 0:6ae2f7bca550 | 132 | static int encode_bytes(void* context, const unsigned char* bytes, size_t length) |
Azure.IoT Build | 0:6ae2f7bca550 | 133 | { |
AzureIoTClient | 28:add19eb7defa | 134 | PAYLOAD* payload = (PAYLOAD*)context; |
AzureIoTClient | 28:add19eb7defa | 135 | (void)memcpy((unsigned char*)payload->bytes + payload->length, bytes, length); |
AzureIoTClient | 28:add19eb7defa | 136 | payload->length += length; |
AzureIoTClient | 28:add19eb7defa | 137 | return 0; |
Azure.IoT Build | 0:6ae2f7bca550 | 138 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 139 | |
Azure.IoT Build | 0:6ae2f7bca550 | 140 | /* Codes_SRS_AMQP_FRAME_CODEC_01_011: [amqp_frame_codec_create shall create an instance of an amqp_frame_codec and return a non-NULL handle to it.] */ |
Azure.IoT Build | 0:6ae2f7bca550 | 141 | AMQP_FRAME_CODEC_HANDLE amqp_frame_codec_create(FRAME_CODEC_HANDLE frame_codec, AMQP_FRAME_RECEIVED_CALLBACK frame_received_callback, |
AzureIoTClient | 28:add19eb7defa | 142 | AMQP_EMPTY_FRAME_RECEIVED_CALLBACK empty_frame_received_callback, AMQP_FRAME_CODEC_ERROR_CALLBACK amqp_frame_codec_error_callback, void* callback_context) |
Azure.IoT Build | 0:6ae2f7bca550 | 143 | { |
AzureIoTClient | 43:4c1e4e94cdd3 | 144 | AMQP_FRAME_CODEC_HANDLE result; |
Azure.IoT Build | 0:6ae2f7bca550 | 145 | |
AzureIoTClient | 28:add19eb7defa | 146 | /* Codes_SRS_AMQP_FRAME_CODEC_01_012: [If any of the arguments frame_codec, frame_received_callback, amqp_frame_codec_error_callback or empty_frame_received_callback is NULL, amqp_frame_codec_create shall return NULL.] */ |
AzureIoTClient | 28:add19eb7defa | 147 | if ((frame_codec == NULL) || |
AzureIoTClient | 28:add19eb7defa | 148 | (frame_received_callback == NULL) || |
AzureIoTClient | 28:add19eb7defa | 149 | (empty_frame_received_callback == NULL) || |
AzureIoTClient | 28:add19eb7defa | 150 | (amqp_frame_codec_error_callback == NULL)) |
AzureIoTClient | 28:add19eb7defa | 151 | { |
AzureIoTClient | 23:1111ee8bcba4 | 152 | LogError("Bad arguments: frame_codec = %p, frame_received_callback = %p, empty_frame_received_callback = %p, amqp_frame_codec_error_callback = %p", |
AzureIoTClient | 23:1111ee8bcba4 | 153 | frame_codec, frame_received_callback, empty_frame_received_callback, amqp_frame_codec_error_callback); |
AzureIoTClient | 28:add19eb7defa | 154 | result = NULL; |
AzureIoTClient | 28:add19eb7defa | 155 | } |
AzureIoTClient | 28:add19eb7defa | 156 | else |
AzureIoTClient | 28:add19eb7defa | 157 | { |
AzureIoTClient | 43:4c1e4e94cdd3 | 158 | result = (AMQP_FRAME_CODEC_HANDLE)malloc(sizeof(AMQP_FRAME_CODEC)); |
AzureIoTClient | 28:add19eb7defa | 159 | /* Codes_SRS_AMQP_FRAME_CODEC_01_020: [If allocating memory for the new amqp_frame_codec fails, then amqp_frame_codec_create shall fail and return NULL.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 160 | if (result == NULL) |
AzureIoTClient | 23:1111ee8bcba4 | 161 | { |
AzureIoTClient | 23:1111ee8bcba4 | 162 | LogError("Could not allocate memory for AMQP frame codec"); |
AzureIoTClient | 23:1111ee8bcba4 | 163 | } |
AzureIoTClient | 23:1111ee8bcba4 | 164 | else |
AzureIoTClient | 23:1111ee8bcba4 | 165 | { |
AzureIoTClient | 28:add19eb7defa | 166 | result->frame_codec = frame_codec; |
AzureIoTClient | 28:add19eb7defa | 167 | result->frame_received_callback = frame_received_callback; |
AzureIoTClient | 28:add19eb7defa | 168 | result->empty_frame_received_callback = empty_frame_received_callback; |
AzureIoTClient | 28:add19eb7defa | 169 | result->error_callback = amqp_frame_codec_error_callback; |
AzureIoTClient | 28:add19eb7defa | 170 | result->callback_context = callback_context; |
AzureIoTClient | 28:add19eb7defa | 171 | result->decode_state = AMQP_FRAME_DECODE_FRAME; |
Azure.IoT Build | 0:6ae2f7bca550 | 172 | |
AzureIoTClient | 28:add19eb7defa | 173 | /* Codes_SRS_AMQP_FRAME_CODEC_01_018: [amqp_frame_codec_create shall create a decoder to be used for decoding AMQP values.] */ |
AzureIoTClient | 28:add19eb7defa | 174 | result->decoder = amqpvalue_decoder_create(amqp_value_decoded, result); |
AzureIoTClient | 28:add19eb7defa | 175 | if (result->decoder == NULL) |
AzureIoTClient | 28:add19eb7defa | 176 | { |
AzureIoTClient | 28:add19eb7defa | 177 | /* Codes_SRS_AMQP_FRAME_CODEC_01_019: [If creating the decoder fails, amqp_frame_codec_create shall fail and return NULL.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 178 | LogError("Could not create AMQP decoder"); |
AzureIoTClient | 23:1111ee8bcba4 | 179 | free(result); |
AzureIoTClient | 28:add19eb7defa | 180 | result = NULL; |
AzureIoTClient | 28:add19eb7defa | 181 | } |
AzureIoTClient | 28:add19eb7defa | 182 | else |
AzureIoTClient | 28:add19eb7defa | 183 | { |
AzureIoTClient | 28:add19eb7defa | 184 | /* Codes_SRS_AMQP_FRAME_CODEC_01_013: [amqp_frame_codec_create shall subscribe for AMQP frames with the given frame_codec.] */ |
AzureIoTClient | 28:add19eb7defa | 185 | if (frame_codec_subscribe(frame_codec, FRAME_TYPE_AMQP, frame_received, result) != 0) |
AzureIoTClient | 28:add19eb7defa | 186 | { |
AzureIoTClient | 28:add19eb7defa | 187 | /* Codes_SRS_AMQP_FRAME_CODEC_01_014: [If subscribing for AMQP frames fails, amqp_frame_codec_create shall fail and return NULL.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 188 | LogError("Could not subscribe for received AMQP frames"); |
AzureIoTClient | 23:1111ee8bcba4 | 189 | amqpvalue_decoder_destroy(result->decoder); |
AzureIoTClient | 28:add19eb7defa | 190 | free(result); |
AzureIoTClient | 28:add19eb7defa | 191 | result = NULL; |
AzureIoTClient | 28:add19eb7defa | 192 | } |
AzureIoTClient | 28:add19eb7defa | 193 | } |
AzureIoTClient | 28:add19eb7defa | 194 | } |
AzureIoTClient | 28:add19eb7defa | 195 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 196 | |
AzureIoTClient | 28:add19eb7defa | 197 | return result; |
Azure.IoT Build | 0:6ae2f7bca550 | 198 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 199 | |
Azure.IoT Build | 0:6ae2f7bca550 | 200 | void amqp_frame_codec_destroy(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec) |
Azure.IoT Build | 0:6ae2f7bca550 | 201 | { |
AzureIoTClient | 23:1111ee8bcba4 | 202 | if (amqp_frame_codec == NULL) |
AzureIoTClient | 23:1111ee8bcba4 | 203 | { |
AzureIoTClient | 23:1111ee8bcba4 | 204 | /* Codes_SRS_AMQP_FRAME_CODEC_01_016: [If amqp_frame_codec is NULL, amqp_frame_codec_destroy shall do nothing.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 205 | LogError("NULL amqp_frame_codec"); |
AzureIoTClient | 23:1111ee8bcba4 | 206 | } |
AzureIoTClient | 23:1111ee8bcba4 | 207 | else |
AzureIoTClient | 23:1111ee8bcba4 | 208 | { |
AzureIoTClient | 28:add19eb7defa | 209 | /* Codes_SRS_AMQP_FRAME_CODEC_01_017: [amqp_frame_codec_destroy shall unsubscribe from receiving AMQP frames from the frame_codec that was passed to amqp_frame_codec_create.] */ |
AzureIoTClient | 28:add19eb7defa | 210 | (void)frame_codec_unsubscribe(amqp_frame_codec->frame_codec, FRAME_TYPE_AMQP); |
Azure.IoT Build | 0:6ae2f7bca550 | 211 | |
AzureIoTClient | 28:add19eb7defa | 212 | /* Codes_SRS_AMQP_FRAME_CODEC_01_021: [The decoder created in amqp_frame_codec_create shall be destroyed by amqp_frame_codec_destroy.] */ |
AzureIoTClient | 28:add19eb7defa | 213 | amqpvalue_decoder_destroy(amqp_frame_codec->decoder); |
Azure.IoT Build | 0:6ae2f7bca550 | 214 | |
AzureIoTClient | 28:add19eb7defa | 215 | /* Codes_SRS_AMQP_FRAME_CODEC_01_015: [amqp_frame_codec_destroy shall free all resources associated with the amqp_frame_codec instance.] */ |
AzureIoTClient | 28:add19eb7defa | 216 | free(amqp_frame_codec); |
AzureIoTClient | 28:add19eb7defa | 217 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 218 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 219 | |
AzureIoTClient | 30:0407b2db334c | 220 | 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) |
Azure.IoT Build | 0:6ae2f7bca550 | 221 | { |
AzureIoTClient | 28:add19eb7defa | 222 | int result; |
Azure.IoT Build | 0:6ae2f7bca550 | 223 | |
AzureIoTClient | 28:add19eb7defa | 224 | /* 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.] */ |
AzureIoTClient | 28:add19eb7defa | 225 | if ((amqp_frame_codec == NULL) || |
AzureIoTClient | 28:add19eb7defa | 226 | (performative == NULL) || |
AzureIoTClient | 28:add19eb7defa | 227 | (on_bytes_encoded == NULL)) |
AzureIoTClient | 28:add19eb7defa | 228 | { |
AzureIoTClient | 23:1111ee8bcba4 | 229 | LogError("Bad arguments: amqp_frame_codec = %p, performative = %p, on_bytes_encoded = %p", |
AzureIoTClient | 23:1111ee8bcba4 | 230 | amqp_frame_codec, performative, on_bytes_encoded); |
AzureIoTClient | 23:1111ee8bcba4 | 231 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 232 | } |
AzureIoTClient | 28:add19eb7defa | 233 | else |
AzureIoTClient | 28:add19eb7defa | 234 | { |
AzureIoTClient | 28:add19eb7defa | 235 | AMQP_VALUE descriptor; |
AzureIoTClient | 28:add19eb7defa | 236 | uint64_t performative_ulong; |
AzureIoTClient | 28:add19eb7defa | 237 | size_t encoded_size; |
Azure.IoT Build | 0:6ae2f7bca550 | 238 | |
AzureIoTClient | 23:1111ee8bcba4 | 239 | if ((descriptor = amqpvalue_get_inplace_descriptor(performative)) == NULL) |
AzureIoTClient | 23:1111ee8bcba4 | 240 | { |
AzureIoTClient | 23:1111ee8bcba4 | 241 | /* 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.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 242 | LogError("Getting the descriptor failed"); |
AzureIoTClient | 23:1111ee8bcba4 | 243 | result = __FAILURE__; |
AzureIoTClient | 23:1111ee8bcba4 | 244 | } |
AzureIoTClient | 23:1111ee8bcba4 | 245 | else if (amqpvalue_get_ulong(descriptor, &performative_ulong) != 0) |
AzureIoTClient | 23:1111ee8bcba4 | 246 | { |
AzureIoTClient | 23:1111ee8bcba4 | 247 | /* 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.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 248 | LogError("Getting the descriptor ulong failed"); |
AzureIoTClient | 23:1111ee8bcba4 | 249 | result = __FAILURE__; |
AzureIoTClient | 23:1111ee8bcba4 | 250 | } |
AzureIoTClient | 28:add19eb7defa | 251 | /* 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.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 252 | else if ((performative_ulong < AMQP_OPEN) || |
AzureIoTClient | 28:add19eb7defa | 253 | (performative_ulong > AMQP_CLOSE)) |
AzureIoTClient | 28:add19eb7defa | 254 | { |
AzureIoTClient | 28:add19eb7defa | 255 | /* 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.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 256 | LogError("Bad arguments: amqp_frame_codec = %p, performative = %p, on_bytes_encoded = %p", |
AzureIoTClient | 23:1111ee8bcba4 | 257 | amqp_frame_codec, performative, on_bytes_encoded); |
AzureIoTClient | 23:1111ee8bcba4 | 258 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 259 | } |
AzureIoTClient | 28:add19eb7defa | 260 | /* 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.] */ |
AzureIoTClient | 28:add19eb7defa | 261 | else if (amqpvalue_get_encoded_size(performative, &encoded_size) != 0) |
AzureIoTClient | 28:add19eb7defa | 262 | { |
AzureIoTClient | 28:add19eb7defa | 263 | /* 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.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 264 | LogError("Getting the encoded size failed"); |
AzureIoTClient | 23:1111ee8bcba4 | 265 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 266 | } |
AzureIoTClient | 28:add19eb7defa | 267 | else |
AzureIoTClient | 28:add19eb7defa | 268 | { |
AzureIoTClient | 28:add19eb7defa | 269 | unsigned char* amqp_performative_bytes = (unsigned char*)malloc(encoded_size); |
AzureIoTClient | 28:add19eb7defa | 270 | if (amqp_performative_bytes == NULL) |
AzureIoTClient | 28:add19eb7defa | 271 | { |
AzureIoTClient | 23:1111ee8bcba4 | 272 | LogError("Could not allocate performative bytes"); |
AzureIoTClient | 23:1111ee8bcba4 | 273 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 274 | } |
AzureIoTClient | 28:add19eb7defa | 275 | else |
AzureIoTClient | 28:add19eb7defa | 276 | { |
AzureIoTClient | 28:add19eb7defa | 277 | PAYLOAD* new_payloads = (PAYLOAD*)malloc(sizeof(PAYLOAD) * (payload_count + 1)); |
AzureIoTClient | 28:add19eb7defa | 278 | if (new_payloads == NULL) |
AzureIoTClient | 28:add19eb7defa | 279 | { |
AzureIoTClient | 23:1111ee8bcba4 | 280 | LogError("Could not allocate frame payloads"); |
AzureIoTClient | 23:1111ee8bcba4 | 281 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 282 | } |
AzureIoTClient | 28:add19eb7defa | 283 | else |
AzureIoTClient | 28:add19eb7defa | 284 | { |
AzureIoTClient | 28:add19eb7defa | 285 | /* 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.] */ |
AzureIoTClient | 28:add19eb7defa | 286 | /* Codes_SRS_AMQP_FRAME_CODEC_01_028: [The encode result for the performative shall be placed in a PAYLOAD structure.] */ |
AzureIoTClient | 28:add19eb7defa | 287 | new_payloads[0].bytes = amqp_performative_bytes; |
AzureIoTClient | 28:add19eb7defa | 288 | new_payloads[0].length = 0; |
Azure.IoT Build | 0:6ae2f7bca550 | 289 | |
AzureIoTClient | 28:add19eb7defa | 290 | if (payload_count > 0) |
AzureIoTClient | 28:add19eb7defa | 291 | { |
AzureIoTClient | 28:add19eb7defa | 292 | (void)memcpy(new_payloads + 1, payloads, sizeof(PAYLOAD) * payload_count); |
AzureIoTClient | 28:add19eb7defa | 293 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 294 | |
AzureIoTClient | 28:add19eb7defa | 295 | if (amqpvalue_encode(performative, encode_bytes, &new_payloads[0]) != 0) |
AzureIoTClient | 28:add19eb7defa | 296 | { |
AzureIoTClient | 23:1111ee8bcba4 | 297 | LogError("amqpvalue_encode failed"); |
AzureIoTClient | 23:1111ee8bcba4 | 298 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 299 | } |
AzureIoTClient | 28:add19eb7defa | 300 | else |
AzureIoTClient | 28:add19eb7defa | 301 | { |
AzureIoTClient | 6:641a9672db08 | 302 | unsigned char channel_bytes[2]; |
AzureIoTClient | 6:641a9672db08 | 303 | |
AzureIoTClient | 6:641a9672db08 | 304 | channel_bytes[0] = channel >> 8; |
AzureIoTClient | 6:641a9672db08 | 305 | channel_bytes[1] = channel & 0xFF; |
Azure.IoT Build | 0:6ae2f7bca550 | 306 | |
AzureIoTClient | 28:add19eb7defa | 307 | /* Codes_SRS_AMQP_FRAME_CODEC_01_005: [Bytes 6 and 7 of an AMQP frame contain the channel number ] */ |
AzureIoTClient | 28:add19eb7defa | 308 | /* Codes_SRS_AMQP_FRAME_CODEC_01_025: [amqp_frame_codec_encode_frame shall encode the frame header by using frame_codec_encode_frame.] */ |
AzureIoTClient | 28:add19eb7defa | 309 | /* Codes_SRS_AMQP_FRAME_CODEC_01_006: [The frame body is defined as a performative followed by an opaque payload.] */ |
AzureIoTClient | 28:add19eb7defa | 310 | 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) |
AzureIoTClient | 28:add19eb7defa | 311 | { |
AzureIoTClient | 28:add19eb7defa | 312 | /* 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.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 313 | LogError("frame_codec_encode_frame failed"); |
AzureIoTClient | 23:1111ee8bcba4 | 314 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 315 | } |
AzureIoTClient | 28:add19eb7defa | 316 | else |
AzureIoTClient | 28:add19eb7defa | 317 | { |
AzureIoTClient | 28:add19eb7defa | 318 | /* 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.] */ |
AzureIoTClient | 28:add19eb7defa | 319 | result = 0; |
AzureIoTClient | 28:add19eb7defa | 320 | } |
AzureIoTClient | 28:add19eb7defa | 321 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 322 | |
AzureIoTClient | 28:add19eb7defa | 323 | free(new_payloads); |
AzureIoTClient | 28:add19eb7defa | 324 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 325 | |
AzureIoTClient | 28:add19eb7defa | 326 | free(amqp_performative_bytes); |
AzureIoTClient | 28:add19eb7defa | 327 | } |
AzureIoTClient | 28:add19eb7defa | 328 | } |
AzureIoTClient | 28:add19eb7defa | 329 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 330 | |
AzureIoTClient | 28:add19eb7defa | 331 | return result; |
Azure.IoT Build | 0:6ae2f7bca550 | 332 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 333 | |
Azure.IoT Build | 0:6ae2f7bca550 | 334 | /* Codes_SRS_AMQP_FRAME_CODEC_01_042: [amqp_frame_codec_encode_empty_frame shall encode a frame with no payload.] */ |
Azure.IoT Build | 0:6ae2f7bca550 | 335 | /* Codes_SRS_AMQP_FRAME_CODEC_01_010: [An AMQP frame with no body MAY be used to generate artificial traffic as needed to satisfy any negotiated idle timeout interval ] */ |
Azure.IoT Build | 0:6ae2f7bca550 | 336 | int amqp_frame_codec_encode_empty_frame(AMQP_FRAME_CODEC_HANDLE amqp_frame_codec, uint16_t channel, ON_BYTES_ENCODED on_bytes_encoded, void* callback_context) |
Azure.IoT Build | 0:6ae2f7bca550 | 337 | { |
AzureIoTClient | 28:add19eb7defa | 338 | int result; |
Azure.IoT Build | 0:6ae2f7bca550 | 339 | |
AzureIoTClient | 28:add19eb7defa | 340 | /* Codes_SRS_AMQP_FRAME_CODEC_01_045: [If amqp_frame_codec is NULL, amqp_frame_codec_encode_empty_frame shall fail and return a non-zero value.] */ |
AzureIoTClient | 28:add19eb7defa | 341 | if (amqp_frame_codec == NULL) |
AzureIoTClient | 28:add19eb7defa | 342 | { |
AzureIoTClient | 23:1111ee8bcba4 | 343 | LogError("NULL amqp_frame_codec"); |
AzureIoTClient | 23:1111ee8bcba4 | 344 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 345 | } |
AzureIoTClient | 28:add19eb7defa | 346 | else |
AzureIoTClient | 28:add19eb7defa | 347 | { |
AzureIoTClient | 6:641a9672db08 | 348 | unsigned char channel_bytes[2]; |
AzureIoTClient | 6:641a9672db08 | 349 | |
AzureIoTClient | 6:641a9672db08 | 350 | channel_bytes[0] = channel >> 8; |
AzureIoTClient | 6:641a9672db08 | 351 | channel_bytes[1] = channel & 0xFF; |
Azure.IoT Build | 0:6ae2f7bca550 | 352 | |
AzureIoTClient | 28:add19eb7defa | 353 | /* Codes_SRS_AMQP_FRAME_CODEC_01_044: [amqp_frame_codec_encode_empty_frame shall use frame_codec_encode_frame to encode the frame.] */ |
AzureIoTClient | 28:add19eb7defa | 354 | if (frame_codec_encode_frame(amqp_frame_codec->frame_codec, FRAME_TYPE_AMQP, NULL, 0, channel_bytes, sizeof(channel_bytes), on_bytes_encoded, callback_context) != 0) |
AzureIoTClient | 28:add19eb7defa | 355 | { |
AzureIoTClient | 28:add19eb7defa | 356 | /* Codes_SRS_AMQP_FRAME_CODEC_01_046: [If encoding fails in any way, amqp_frame_codec_encode_empty_frame shall fail and return a non-zero value.] */ |
AzureIoTClient | 23:1111ee8bcba4 | 357 | LogError("frame_codec_encode_frame failed when encoding empty frame"); |
AzureIoTClient | 23:1111ee8bcba4 | 358 | result = __FAILURE__; |
AzureIoTClient | 28:add19eb7defa | 359 | } |
AzureIoTClient | 28:add19eb7defa | 360 | else |
AzureIoTClient | 28:add19eb7defa | 361 | { |
AzureIoTClient | 28:add19eb7defa | 362 | /* Codes_SRS_AMQP_FRAME_CODEC_01_043: [On success, amqp_frame_codec_encode_empty_frame shall return 0.] */ |
AzureIoTClient | 28:add19eb7defa | 363 | result = 0; |
AzureIoTClient | 28:add19eb7defa | 364 | } |
AzureIoTClient | 28:add19eb7defa | 365 | } |
Azure.IoT Build | 0:6ae2f7bca550 | 366 | |
AzureIoTClient | 28:add19eb7defa | 367 | return result; |
Azure.IoT Build | 0:6ae2f7bca550 | 368 | } |