A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Committer:
AzureIoTClient
Date:
Tue Jan 30 08:21:55 2018 -0800
Revision:
38:7631b92cc772
Parent:
35:d0bed2404ee9
Child:
41:0e723f9cbd89
1.1.31

Who changed what in which revision?

UserRevisionLine numberNew 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 <string.h>
Azure.IoT Build 0:6ae2f7bca550 6
AzureIoTClient 19:000ab4e6a2c1 7 #include "azure_c_shared_utility/optimize_size.h"
AzureIoTClient 21:f9c433d8e6ca 8 #include "azure_c_shared_utility/gballoc.h"
Azure.IoT Build 0:6ae2f7bca550 9 #include "azure_c_shared_utility/xio.h"
Azure.IoT Build 0:6ae2f7bca550 10 #include "azure_c_shared_utility/xlogging.h"
Azure.IoT Build 0:6ae2f7bca550 11 #include "azure_c_shared_utility/tickcounter.h"
Azure.IoT Build 0:6ae2f7bca550 12
Azure.IoT Build 0:6ae2f7bca550 13 #include "azure_uamqp_c/connection.h"
Azure.IoT Build 0:6ae2f7bca550 14 #include "azure_uamqp_c/frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 15 #include "azure_uamqp_c/amqp_frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 16 #include "azure_uamqp_c/amqp_definitions.h"
Azure.IoT Build 0:6ae2f7bca550 17 #include "azure_uamqp_c/amqpvalue_to_string.h"
Azure.IoT Build 0:6ae2f7bca550 18
Azure.IoT Build 0:6ae2f7bca550 19 /* Requirements satisfied by the virtue of implementing the ISO:*/
Azure.IoT Build 0:6ae2f7bca550 20 /* Codes_SRS_CONNECTION_01_088: [Any data appearing beyond the protocol header MUST match the version indicated by the protocol header.] */
Azure.IoT Build 0:6ae2f7bca550 21 /* Codes_SRS_CONNECTION_01_015: [Implementations SHOULD NOT expect to be able to reuse open TCP sockets after close performatives have been exchanged.] */
Azure.IoT Build 0:6ae2f7bca550 22
AzureIoTClient 16:22a72cf8e416 23 /* Codes_SRS_CONNECTION_01_087: [The protocol header consists of the upper case ASCII letters "AMQP" followed by a protocol id of zero, followed by three unsigned bytes representing the major, minor, and revision of the protocol version (currently 1 (MAJOR), 0 (MINOR), 0 (REVISION)). In total this is an 8-octet sequence] */
Azure.IoT Build 0:6ae2f7bca550 24 static const unsigned char amqp_header[] = { 'A', 'M', 'Q', 'P', 0, 1, 0, 0 };
Azure.IoT Build 0:6ae2f7bca550 25
Azure.IoT Build 0:6ae2f7bca550 26 typedef enum RECEIVE_FRAME_STATE_TAG
Azure.IoT Build 0:6ae2f7bca550 27 {
AzureIoTClient 4:98007eb79fa8 28 RECEIVE_FRAME_STATE_FRAME_SIZE,
AzureIoTClient 4:98007eb79fa8 29 RECEIVE_FRAME_STATE_FRAME_DATA
Azure.IoT Build 0:6ae2f7bca550 30 } RECEIVE_FRAME_STATE;
Azure.IoT Build 0:6ae2f7bca550 31
Azure.IoT Build 0:6ae2f7bca550 32 typedef struct ENDPOINT_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 33 {
AzureIoTClient 4:98007eb79fa8 34 uint16_t incoming_channel;
AzureIoTClient 4:98007eb79fa8 35 uint16_t outgoing_channel;
AzureIoTClient 4:98007eb79fa8 36 ON_ENDPOINT_FRAME_RECEIVED on_endpoint_frame_received;
AzureIoTClient 4:98007eb79fa8 37 ON_CONNECTION_STATE_CHANGED on_connection_state_changed;
AzureIoTClient 4:98007eb79fa8 38 void* callback_context;
AzureIoTClient 4:98007eb79fa8 39 CONNECTION_HANDLE connection;
Azure.IoT Build 0:6ae2f7bca550 40 } ENDPOINT_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 41
Azure.IoT Build 0:6ae2f7bca550 42 typedef struct CONNECTION_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 43 {
AzureIoTClient 4:98007eb79fa8 44 XIO_HANDLE io;
AzureIoTClient 4:98007eb79fa8 45 size_t header_bytes_received;
AzureIoTClient 4:98007eb79fa8 46 CONNECTION_STATE connection_state;
AzureIoTClient 4:98007eb79fa8 47 FRAME_CODEC_HANDLE frame_codec;
AzureIoTClient 4:98007eb79fa8 48 AMQP_FRAME_CODEC_HANDLE amqp_frame_codec;
AzureIoTClient 4:98007eb79fa8 49 ENDPOINT_INSTANCE** endpoints;
AzureIoTClient 4:98007eb79fa8 50 uint32_t endpoint_count;
AzureIoTClient 4:98007eb79fa8 51 char* host_name;
AzureIoTClient 4:98007eb79fa8 52 char* container_id;
AzureIoTClient 4:98007eb79fa8 53 TICK_COUNTER_HANDLE tick_counter;
AzureIoTClient 4:98007eb79fa8 54 uint32_t remote_max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 55
AzureIoTClient 4:98007eb79fa8 56 ON_SEND_COMPLETE on_send_complete;
AzureIoTClient 4:98007eb79fa8 57 void* on_send_complete_callback_context;
Azure.IoT Build 0:6ae2f7bca550 58
AzureIoTClient 4:98007eb79fa8 59 ON_NEW_ENDPOINT on_new_endpoint;
AzureIoTClient 4:98007eb79fa8 60 void* on_new_endpoint_callback_context;
Azure.IoT Build 0:6ae2f7bca550 61
Azure.IoT Build 0:6ae2f7bca550 62 ON_CONNECTION_STATE_CHANGED on_connection_state_changed;
Azure.IoT Build 0:6ae2f7bca550 63 void* on_connection_state_changed_callback_context;
Azure.IoT Build 0:6ae2f7bca550 64 ON_IO_ERROR on_io_error;
Azure.IoT Build 0:6ae2f7bca550 65 void* on_io_error_callback_context;
Azure.IoT Build 0:6ae2f7bca550 66
AzureIoTClient 4:98007eb79fa8 67 /* options */
AzureIoTClient 4:98007eb79fa8 68 uint32_t max_frame_size;
AzureIoTClient 4:98007eb79fa8 69 uint16_t channel_max;
AzureIoTClient 4:98007eb79fa8 70 milliseconds idle_timeout;
AzureIoTClient 4:98007eb79fa8 71 milliseconds remote_idle_timeout;
AzureIoTClient 35:d0bed2404ee9 72 milliseconds remote_idle_timeout_send_frame_millisecond;
AzureIoTClient 35:d0bed2404ee9 73 double idle_timeout_empty_frame_send_ratio;
Azure.IoT.Build 14:0b0e28c75ded 74 tickcounter_ms_t last_frame_received_time;
Azure.IoT.Build 14:0b0e28c75ded 75 tickcounter_ms_t last_frame_sent_time;
Azure.IoT Build 0:6ae2f7bca550 76
AzureIoTClient 4:98007eb79fa8 77 unsigned int is_underlying_io_open : 1;
AzureIoTClient 4:98007eb79fa8 78 unsigned int idle_timeout_specified : 1;
AzureIoTClient 4:98007eb79fa8 79 unsigned int is_remote_frame_received : 1;
AzureIoTClient 4:98007eb79fa8 80 unsigned int is_trace_on : 1;
Azure.IoT Build 0:6ae2f7bca550 81 } CONNECTION_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 82
Azure.IoT Build 0:6ae2f7bca550 83 /* Codes_SRS_CONNECTION_01_258: [on_connection_state_changed shall be invoked whenever the connection state changes.]*/
AzureIoTClient 24:2c59c2d43ebf 84 static void connection_set_state(CONNECTION_HANDLE connection, CONNECTION_STATE connection_state)
Azure.IoT Build 0:6ae2f7bca550 85 {
AzureIoTClient 4:98007eb79fa8 86 uint64_t i;
Azure.IoT Build 0:6ae2f7bca550 87
AzureIoTClient 24:2c59c2d43ebf 88 CONNECTION_STATE previous_state = connection->connection_state;
AzureIoTClient 24:2c59c2d43ebf 89 connection->connection_state = connection_state;
Azure.IoT Build 0:6ae2f7bca550 90
Azure.IoT Build 0:6ae2f7bca550 91 /* Codes_SRS_CONNECTION_22_001: [If a connection state changed occurs and a callback is registered the callback shall be called.] */
AzureIoTClient 24:2c59c2d43ebf 92 if (connection->on_connection_state_changed)
Azure.IoT Build 0:6ae2f7bca550 93 {
AzureIoTClient 24:2c59c2d43ebf 94 connection->on_connection_state_changed(connection->on_connection_state_changed_callback_context, connection_state, previous_state);
Azure.IoT Build 0:6ae2f7bca550 95 }
Azure.IoT Build 0:6ae2f7bca550 96
AzureIoTClient 16:22a72cf8e416 97 /* Codes_SRS_CONNECTION_01_260: [Each endpoint's on_connection_state_changed shall be called.] */
AzureIoTClient 24:2c59c2d43ebf 98 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 99 {
AzureIoTClient 4:98007eb79fa8 100 /* Codes_SRS_CONNECTION_01_259: [The callback_context passed in connection_create_endpoint.] */
AzureIoTClient 24:2c59c2d43ebf 101 connection->endpoints[i]->on_connection_state_changed(connection->endpoints[i]->callback_context, connection_state, previous_state);
AzureIoTClient 4:98007eb79fa8 102 }
Azure.IoT Build 0:6ae2f7bca550 103 }
Azure.IoT Build 0:6ae2f7bca550 104
AzureIoTClient 38:7631b92cc772 105 // This callback usage needs to be either verified and commented or integrated into
AzureIoTClient 38:7631b92cc772 106 // the state machine.
AzureIoTClient 38:7631b92cc772 107 static void unchecked_on_send_complete(void* context, IO_SEND_RESULT send_result)
AzureIoTClient 38:7631b92cc772 108 {
AzureIoTClient 38:7631b92cc772 109 (void)context;
AzureIoTClient 38:7631b92cc772 110 (void)send_result;
AzureIoTClient 38:7631b92cc772 111 }
AzureIoTClient 38:7631b92cc772 112
AzureIoTClient 24:2c59c2d43ebf 113 static int send_header(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 114 {
AzureIoTClient 4:98007eb79fa8 115 int result;
Azure.IoT Build 0:6ae2f7bca550 116
AzureIoTClient 16:22a72cf8e416 117 /* Codes_SRS_CONNECTION_01_093: [_ When the client opens a new socket connection to a server, it MUST send a protocol header with the client's preferred protocol version.] */
AzureIoTClient 4:98007eb79fa8 118 /* Codes_SRS_CONNECTION_01_104: [Sending the protocol header shall be done by using xio_send.] */
AzureIoTClient 38:7631b92cc772 119 if (xio_send(connection->io, amqp_header, sizeof(amqp_header), unchecked_on_send_complete, NULL) != 0)
AzureIoTClient 4:98007eb79fa8 120 {
AzureIoTClient 4:98007eb79fa8 121 /* Codes_SRS_CONNECTION_01_106: [When sending the protocol header fails, the connection shall be immediately closed.] */
AzureIoTClient 28:add19eb7defa 122 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 123 {
AzureIoTClient 28:add19eb7defa 124 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 125 }
Azure.IoT Build 0:6ae2f7bca550 126
AzureIoTClient 4:98007eb79fa8 127 /* Codes_SRS_CONNECTION_01_057: [END In this state it is illegal for either endpoint to write anything more onto the connection. The connection can be safely closed and discarded.] */
AzureIoTClient 24:2c59c2d43ebf 128 connection_set_state(connection, CONNECTION_STATE_END);
Azure.IoT Build 0:6ae2f7bca550 129
AzureIoTClient 4:98007eb79fa8 130 /* Codes_SRS_CONNECTION_01_105: [When xio_send fails, connection_dowork shall return a non-zero value.] */
AzureIoTClient 19:000ab4e6a2c1 131 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 132 }
AzureIoTClient 4:98007eb79fa8 133 else
AzureIoTClient 4:98007eb79fa8 134 {
AzureIoTClient 24:2c59c2d43ebf 135 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 136 {
AzureIoTClient 16:22a72cf8e416 137 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Header (AMQP 0.1.0.0)");
AzureIoTClient 4:98007eb79fa8 138 }
Azure.IoT Build 0:6ae2f7bca550 139
AzureIoTClient 4:98007eb79fa8 140 /* Codes_SRS_CONNECTION_01_041: [HDR SENT In this state the connection header has been sent to the peer but no connection header has been received.] */
AzureIoTClient 24:2c59c2d43ebf 141 connection_set_state(connection, CONNECTION_STATE_HDR_SENT);
AzureIoTClient 4:98007eb79fa8 142 result = 0;
AzureIoTClient 4:98007eb79fa8 143 }
Azure.IoT Build 0:6ae2f7bca550 144
AzureIoTClient 4:98007eb79fa8 145 return result;
Azure.IoT Build 0:6ae2f7bca550 146 }
Azure.IoT Build 0:6ae2f7bca550 147
Azure.IoT Build 0:6ae2f7bca550 148 static const char* get_frame_type_as_string(AMQP_VALUE descriptor)
Azure.IoT Build 0:6ae2f7bca550 149 {
AzureIoTClient 4:98007eb79fa8 150 const char* result;
Azure.IoT Build 0:6ae2f7bca550 151
AzureIoTClient 4:98007eb79fa8 152 if (is_open_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 153 {
AzureIoTClient 4:98007eb79fa8 154 result = "[OPEN]";
AzureIoTClient 4:98007eb79fa8 155 }
AzureIoTClient 4:98007eb79fa8 156 else if (is_begin_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 157 {
AzureIoTClient 4:98007eb79fa8 158 result = "[BEGIN]";
AzureIoTClient 4:98007eb79fa8 159 }
AzureIoTClient 4:98007eb79fa8 160 else if (is_attach_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 161 {
AzureIoTClient 4:98007eb79fa8 162 result = "[ATTACH]";
AzureIoTClient 4:98007eb79fa8 163 }
AzureIoTClient 4:98007eb79fa8 164 else if (is_flow_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 165 {
AzureIoTClient 4:98007eb79fa8 166 result = "[FLOW]";
AzureIoTClient 4:98007eb79fa8 167 }
AzureIoTClient 4:98007eb79fa8 168 else if (is_disposition_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 169 {
AzureIoTClient 4:98007eb79fa8 170 result = "[DISPOSITION]";
AzureIoTClient 4:98007eb79fa8 171 }
AzureIoTClient 4:98007eb79fa8 172 else if (is_transfer_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 173 {
AzureIoTClient 4:98007eb79fa8 174 result = "[TRANSFER]";
AzureIoTClient 4:98007eb79fa8 175 }
AzureIoTClient 4:98007eb79fa8 176 else if (is_detach_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 177 {
AzureIoTClient 4:98007eb79fa8 178 result = "[DETACH]";
AzureIoTClient 4:98007eb79fa8 179 }
AzureIoTClient 4:98007eb79fa8 180 else if (is_end_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 181 {
AzureIoTClient 4:98007eb79fa8 182 result = "[END]";
AzureIoTClient 4:98007eb79fa8 183 }
AzureIoTClient 4:98007eb79fa8 184 else if (is_close_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 185 {
AzureIoTClient 4:98007eb79fa8 186 result = "[CLOSE]";
AzureIoTClient 4:98007eb79fa8 187 }
AzureIoTClient 4:98007eb79fa8 188 else
AzureIoTClient 4:98007eb79fa8 189 {
AzureIoTClient 4:98007eb79fa8 190 result = "[Unknown]";
AzureIoTClient 4:98007eb79fa8 191 }
Azure.IoT Build 0:6ae2f7bca550 192
AzureIoTClient 4:98007eb79fa8 193 return result;
Azure.IoT Build 0:6ae2f7bca550 194 }
Azure.IoT Build 0:6ae2f7bca550 195
Azure.IoT Build 5:ae49385aff34 196 static void log_incoming_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 197 {
AzureIoTClient 9:c22db038556c 198 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 199 UNUSED(performative);
AzureIoTClient 9:c22db038556c 200 #else
AzureIoTClient 4:98007eb79fa8 201 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 28:add19eb7defa 202 if (descriptor == NULL)
AzureIoTClient 28:add19eb7defa 203 {
AzureIoTClient 28:add19eb7defa 204 LogError("Error getting performative descriptor");
AzureIoTClient 28:add19eb7defa 205 }
AzureIoTClient 28:add19eb7defa 206 else
AzureIoTClient 28:add19eb7defa 207 {
AzureIoTClient 28:add19eb7defa 208 char* performative_as_string;
AzureIoTClient 16:22a72cf8e416 209 LOG(AZ_LOG_TRACE, 0, "<- ");
AzureIoTClient 16:22a72cf8e416 210 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 211 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 212 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 4:98007eb79fa8 213 if (performative_as_string != NULL)
AzureIoTClient 4:98007eb79fa8 214 {
AzureIoTClient 21:f9c433d8e6ca 215 free(performative_as_string);
AzureIoTClient 4:98007eb79fa8 216 }
AzureIoTClient 4:98007eb79fa8 217 }
AzureIoTClient 9:c22db038556c 218 #endif
Azure.IoT Build 0:6ae2f7bca550 219 }
Azure.IoT Build 0:6ae2f7bca550 220
Azure.IoT Build 5:ae49385aff34 221 static void log_outgoing_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 222 {
AzureIoTClient 9:c22db038556c 223 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 224 UNUSED(performative);
AzureIoTClient 9:c22db038556c 225 #else
AzureIoTClient 4:98007eb79fa8 226 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 28:add19eb7defa 227 if (descriptor == NULL)
AzureIoTClient 28:add19eb7defa 228 {
AzureIoTClient 28:add19eb7defa 229 LogError("Error getting performative descriptor");
AzureIoTClient 28:add19eb7defa 230 }
AzureIoTClient 28:add19eb7defa 231 else
AzureIoTClient 28:add19eb7defa 232 {
AzureIoTClient 28:add19eb7defa 233 char* performative_as_string;
AzureIoTClient 28:add19eb7defa 234 LOG(AZ_LOG_TRACE, 0, "-> ");
AzureIoTClient 16:22a72cf8e416 235 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 236 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 237 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 4:98007eb79fa8 238 if (performative_as_string != NULL)
AzureIoTClient 4:98007eb79fa8 239 {
AzureIoTClient 21:f9c433d8e6ca 240 free(performative_as_string);
AzureIoTClient 4:98007eb79fa8 241 }
AzureIoTClient 4:98007eb79fa8 242 }
AzureIoTClient 9:c22db038556c 243 #endif
Azure.IoT Build 0:6ae2f7bca550 244 }
Azure.IoT Build 0:6ae2f7bca550 245
Azure.IoT Build 0:6ae2f7bca550 246 static void on_bytes_encoded(void* context, const unsigned char* bytes, size_t length, bool encode_complete)
Azure.IoT Build 0:6ae2f7bca550 247 {
AzureIoTClient 24:2c59c2d43ebf 248 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 38:7631b92cc772 249 if (xio_send(connection->io, bytes, length,
AzureIoTClient 38:7631b92cc772 250 (encode_complete && connection->on_send_complete != NULL) ? connection->on_send_complete : unchecked_on_send_complete,
AzureIoTClient 38:7631b92cc772 251 connection->on_send_complete_callback_context) != 0)
AzureIoTClient 4:98007eb79fa8 252 {
AzureIoTClient 28:add19eb7defa 253 LogError("Cannot send encoded bytes");
AzureIoTClient 24:2c59c2d43ebf 254
AzureIoTClient 28:add19eb7defa 255 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 256 {
AzureIoTClient 28:add19eb7defa 257 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 258 }
AzureIoTClient 24:2c59c2d43ebf 259
AzureIoTClient 24:2c59c2d43ebf 260 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 261 }
Azure.IoT Build 0:6ae2f7bca550 262 }
Azure.IoT Build 0:6ae2f7bca550 263
AzureIoTClient 24:2c59c2d43ebf 264 static int send_open_frame(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 265 {
AzureIoTClient 4:98007eb79fa8 266 int result;
Azure.IoT Build 0:6ae2f7bca550 267
AzureIoTClient 4:98007eb79fa8 268 /* Codes_SRS_CONNECTION_01_151: [The connection max_frame_size setting shall be passed down to the frame_codec when the Open frame is sent.] */
AzureIoTClient 24:2c59c2d43ebf 269 if (frame_codec_set_max_frame_size(connection->frame_codec, connection->max_frame_size) != 0)
AzureIoTClient 4:98007eb79fa8 270 {
AzureIoTClient 28:add19eb7defa 271 LogError("Cannot set max frame size");
AzureIoTClient 24:2c59c2d43ebf 272
AzureIoTClient 4:98007eb79fa8 273 /* Codes_SRS_CONNECTION_01_207: [If frame_codec_set_max_frame_size fails the connection shall be closed and the state set to END.] */
AzureIoTClient 28:add19eb7defa 274 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 275 {
AzureIoTClient 28:add19eb7defa 276 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 277 }
AzureIoTClient 24:2c59c2d43ebf 278
AzureIoTClient 28:add19eb7defa 279 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 280 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 281 }
AzureIoTClient 4:98007eb79fa8 282 else
AzureIoTClient 4:98007eb79fa8 283 {
AzureIoTClient 4:98007eb79fa8 284 /* Codes_SRS_CONNECTION_01_134: [The container id field shall be filled with the container id specified in connection_create.] */
AzureIoTClient 24:2c59c2d43ebf 285 OPEN_HANDLE open_performative = open_create(connection->container_id);
AzureIoTClient 4:98007eb79fa8 286 if (open_performative == NULL)
AzureIoTClient 4:98007eb79fa8 287 {
AzureIoTClient 28:add19eb7defa 288 LogError("Cannot create OPEN performative");
AzureIoTClient 28:add19eb7defa 289
AzureIoTClient 28:add19eb7defa 290 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 291 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 292 {
AzureIoTClient 28:add19eb7defa 293 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 294 }
AzureIoTClient 24:2c59c2d43ebf 295
AzureIoTClient 28:add19eb7defa 296 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 297 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 298 }
AzureIoTClient 4:98007eb79fa8 299 else
AzureIoTClient 4:98007eb79fa8 300 {
AzureIoTClient 4:98007eb79fa8 301 /* Codes_SRS_CONNECTION_01_137: [The max_frame_size connection setting shall be set in the open frame by using open_set_max_frame_size.] */
AzureIoTClient 24:2c59c2d43ebf 302 if (open_set_max_frame_size(open_performative, connection->max_frame_size) != 0)
AzureIoTClient 4:98007eb79fa8 303 {
AzureIoTClient 28:add19eb7defa 304 LogError("Cannot set max frame size");
AzureIoTClient 24:2c59c2d43ebf 305
AzureIoTClient 28:add19eb7defa 306 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 307 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 308 {
AzureIoTClient 28:add19eb7defa 309 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 310 }
AzureIoTClient 24:2c59c2d43ebf 311
AzureIoTClient 28:add19eb7defa 312 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 313 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 314 }
AzureIoTClient 4:98007eb79fa8 315 /* Codes_SRS_CONNECTION_01_139: [The channel_max connection setting shall be set in the open frame by using open_set_channel_max.] */
AzureIoTClient 24:2c59c2d43ebf 316 else if (open_set_channel_max(open_performative, connection->channel_max) != 0)
AzureIoTClient 4:98007eb79fa8 317 {
AzureIoTClient 28:add19eb7defa 318 LogError("Cannot set max channel");
AzureIoTClient 24:2c59c2d43ebf 319
AzureIoTClient 28:add19eb7defa 320 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 321 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 322 {
AzureIoTClient 28:add19eb7defa 323 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 324 }
AzureIoTClient 24:2c59c2d43ebf 325
AzureIoTClient 28:add19eb7defa 326 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 327 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 328 }
AzureIoTClient 4:98007eb79fa8 329 /* Codes_SRS_CONNECTION_01_142: [If no idle_timeout value has been specified, no value shall be stamped in the open frame (no call to open_set_idle_time_out shall be made).] */
AzureIoTClient 24:2c59c2d43ebf 330 else if ((connection->idle_timeout_specified) &&
AzureIoTClient 4:98007eb79fa8 331 /* Codes_SRS_CONNECTION_01_141: [If idle_timeout has been specified by a call to connection_set_idle_timeout, then that value shall be stamped in the open frame.] */
AzureIoTClient 24:2c59c2d43ebf 332 (open_set_idle_time_out(open_performative, connection->idle_timeout) != 0))
AzureIoTClient 4:98007eb79fa8 333 {
AzureIoTClient 4:98007eb79fa8 334 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 335 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 336 {
AzureIoTClient 28:add19eb7defa 337 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 338 }
AzureIoTClient 24:2c59c2d43ebf 339
AzureIoTClient 28:add19eb7defa 340 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 341 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 342 }
AzureIoTClient 4:98007eb79fa8 343 /* Codes_SRS_CONNECTION_01_136: [If no hostname value has been specified, no value shall be stamped in the open frame (no call to open_set_hostname shall be made).] */
AzureIoTClient 24:2c59c2d43ebf 344 else if ((connection->host_name != NULL) &&
AzureIoTClient 4:98007eb79fa8 345 /* Codes_SRS_CONNECTION_01_135: [If hostname has been specified by a call to connection_set_hostname, then that value shall be stamped in the open frame.] */
AzureIoTClient 24:2c59c2d43ebf 346 (open_set_hostname(open_performative, connection->host_name) != 0))
AzureIoTClient 4:98007eb79fa8 347 {
AzureIoTClient 28:add19eb7defa 348 LogError("Cannot set hostname");
AzureIoTClient 24:2c59c2d43ebf 349
AzureIoTClient 28:add19eb7defa 350 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 351 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 352 {
AzureIoTClient 28:add19eb7defa 353 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 354 }
AzureIoTClient 24:2c59c2d43ebf 355
AzureIoTClient 28:add19eb7defa 356 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 357 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 358 }
AzureIoTClient 4:98007eb79fa8 359 else
AzureIoTClient 4:98007eb79fa8 360 {
AzureIoTClient 4:98007eb79fa8 361 AMQP_VALUE open_performative_value = amqpvalue_create_open(open_performative);
AzureIoTClient 4:98007eb79fa8 362 if (open_performative_value == NULL)
AzureIoTClient 4:98007eb79fa8 363 {
AzureIoTClient 28:add19eb7defa 364 LogError("Cannot create OPEN AMQP value");
AzureIoTClient 24:2c59c2d43ebf 365
AzureIoTClient 28:add19eb7defa 366 /* Codes_SRS_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 367 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 368 {
AzureIoTClient 28:add19eb7defa 369 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 370 }
AzureIoTClient 24:2c59c2d43ebf 371
AzureIoTClient 28:add19eb7defa 372 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 373 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 374 }
AzureIoTClient 4:98007eb79fa8 375 else
AzureIoTClient 4:98007eb79fa8 376 {
AzureIoTClient 4:98007eb79fa8 377 /* Codes_SRS_CONNECTION_01_002: [Each AMQP connection begins with an exchange of capabilities and limitations, including the maximum frame size.] */
AzureIoTClient 4:98007eb79fa8 378 /* Codes_SRS_CONNECTION_01_004: [After establishing or accepting a TCP connection and sending the protocol header, each peer MUST send an open frame before sending any other frames.] */
AzureIoTClient 4:98007eb79fa8 379 /* Codes_SRS_CONNECTION_01_005: [The open frame describes the capabilities and limits of that peer.] */
AzureIoTClient 4:98007eb79fa8 380 /* Codes_SRS_CONNECTION_01_205: [Sending the AMQP OPEN frame shall be done by calling amqp_frame_codec_begin_encode_frame with channel number 0, the actual performative payload and 0 as payload_size.] */
AzureIoTClient 4:98007eb79fa8 381 /* Codes_SRS_CONNECTION_01_006: [The open frame can only be sent on channel 0.] */
AzureIoTClient 28:add19eb7defa 382 connection->on_send_complete = NULL;
AzureIoTClient 28:add19eb7defa 383 connection->on_send_complete_callback_context = NULL;
AzureIoTClient 24:2c59c2d43ebf 384 if (amqp_frame_codec_encode_frame(connection->amqp_frame_codec, 0, open_performative_value, NULL, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 385 {
AzureIoTClient 28:add19eb7defa 386 LogError("amqp_frame_codec_encode_frame failed");
AzureIoTClient 24:2c59c2d43ebf 387
AzureIoTClient 28:add19eb7defa 388 /* Codes_SRS_CONNECTION_01_206: [If sending the frame fails, the connection shall be closed and state set to END.] */
AzureIoTClient 28:add19eb7defa 389 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 390 {
AzureIoTClient 28:add19eb7defa 391 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 392 }
AzureIoTClient 24:2c59c2d43ebf 393
AzureIoTClient 28:add19eb7defa 394 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 395 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 396 }
AzureIoTClient 4:98007eb79fa8 397 else
AzureIoTClient 4:98007eb79fa8 398 {
AzureIoTClient 24:2c59c2d43ebf 399 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 400 {
Azure.IoT Build 5:ae49385aff34 401 log_outgoing_frame(open_performative_value);
AzureIoTClient 4:98007eb79fa8 402 }
Azure.IoT Build 0:6ae2f7bca550 403
AzureIoTClient 4:98007eb79fa8 404 /* Codes_SRS_CONNECTION_01_046: [OPEN SENT In this state the connection headers have been exchanged. An open frame has been sent to the peer but no open frame has yet been received.] */
AzureIoTClient 24:2c59c2d43ebf 405 connection_set_state(connection, CONNECTION_STATE_OPEN_SENT);
AzureIoTClient 4:98007eb79fa8 406 result = 0;
AzureIoTClient 4:98007eb79fa8 407 }
Azure.IoT Build 0:6ae2f7bca550 408
AzureIoTClient 4:98007eb79fa8 409 amqpvalue_destroy(open_performative_value);
AzureIoTClient 4:98007eb79fa8 410 }
AzureIoTClient 4:98007eb79fa8 411 }
Azure.IoT Build 0:6ae2f7bca550 412
AzureIoTClient 4:98007eb79fa8 413 open_destroy(open_performative);
AzureIoTClient 4:98007eb79fa8 414 }
AzureIoTClient 4:98007eb79fa8 415 }
Azure.IoT Build 0:6ae2f7bca550 416
AzureIoTClient 4:98007eb79fa8 417 return result;
Azure.IoT Build 0:6ae2f7bca550 418 }
Azure.IoT Build 0:6ae2f7bca550 419
AzureIoTClient 24:2c59c2d43ebf 420 static int send_close_frame(CONNECTION_HANDLE connection, ERROR_HANDLE error_handle)
Azure.IoT Build 0:6ae2f7bca550 421 {
AzureIoTClient 4:98007eb79fa8 422 int result;
AzureIoTClient 4:98007eb79fa8 423 CLOSE_HANDLE close_performative;
Azure.IoT Build 0:6ae2f7bca550 424
AzureIoTClient 4:98007eb79fa8 425 /* Codes_SRS_CONNECTION_01_217: [The CLOSE frame shall be constructed by using close_create.] */
AzureIoTClient 4:98007eb79fa8 426 close_performative = close_create();
AzureIoTClient 4:98007eb79fa8 427 if (close_performative == NULL)
AzureIoTClient 4:98007eb79fa8 428 {
AzureIoTClient 28:add19eb7defa 429 LogError("Cannot create close performative");
AzureIoTClient 28:add19eb7defa 430 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 431 }
AzureIoTClient 4:98007eb79fa8 432 else
AzureIoTClient 4:98007eb79fa8 433 {
AzureIoTClient 4:98007eb79fa8 434 if ((error_handle != NULL) &&
AzureIoTClient 4:98007eb79fa8 435 /* Codes_SRS_CONNECTION_01_238: [If set, this field indicates that the connection is being closed due to an error condition.] */
AzureIoTClient 4:98007eb79fa8 436 (close_set_error(close_performative, error_handle) != 0))
AzureIoTClient 4:98007eb79fa8 437 {
AzureIoTClient 28:add19eb7defa 438 LogError("Cannot set error on CLOSE");
AzureIoTClient 28:add19eb7defa 439 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 440 }
AzureIoTClient 4:98007eb79fa8 441 else
AzureIoTClient 4:98007eb79fa8 442 {
AzureIoTClient 4:98007eb79fa8 443 AMQP_VALUE close_performative_value = amqpvalue_create_close(close_performative);
AzureIoTClient 4:98007eb79fa8 444 if (close_performative_value == NULL)
AzureIoTClient 4:98007eb79fa8 445 {
AzureIoTClient 28:add19eb7defa 446 LogError("Cannot create AMQP CLOSE performative value");
AzureIoTClient 28:add19eb7defa 447 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 448 }
AzureIoTClient 4:98007eb79fa8 449 else
AzureIoTClient 4:98007eb79fa8 450 {
AzureIoTClient 4:98007eb79fa8 451 /* Codes_SRS_CONNECTION_01_215: [Sending the AMQP CLOSE frame shall be done by calling amqp_frame_codec_begin_encode_frame with channel number 0, the actual performative payload and 0 as payload_size.] */
AzureIoTClient 4:98007eb79fa8 452 /* Codes_SRS_CONNECTION_01_013: [However, implementations SHOULD send it on channel 0] */
AzureIoTClient 28:add19eb7defa 453 connection->on_send_complete = NULL;
AzureIoTClient 28:add19eb7defa 454 connection->on_send_complete_callback_context = NULL;
AzureIoTClient 24:2c59c2d43ebf 455 if (amqp_frame_codec_encode_frame(connection->amqp_frame_codec, 0, close_performative_value, NULL, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 456 {
AzureIoTClient 28:add19eb7defa 457 LogError("amqp_frame_codec_encode_frame failed");
AzureIoTClient 28:add19eb7defa 458 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 459 }
AzureIoTClient 4:98007eb79fa8 460 else
AzureIoTClient 4:98007eb79fa8 461 {
AzureIoTClient 24:2c59c2d43ebf 462 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 463 {
Azure.IoT Build 5:ae49385aff34 464 log_outgoing_frame(close_performative_value);
AzureIoTClient 4:98007eb79fa8 465 }
Azure.IoT Build 5:ae49385aff34 466
AzureIoTClient 4:98007eb79fa8 467 result = 0;
AzureIoTClient 4:98007eb79fa8 468 }
Azure.IoT Build 0:6ae2f7bca550 469
AzureIoTClient 4:98007eb79fa8 470 amqpvalue_destroy(close_performative_value);
AzureIoTClient 4:98007eb79fa8 471 }
AzureIoTClient 4:98007eb79fa8 472 }
Azure.IoT Build 0:6ae2f7bca550 473
AzureIoTClient 4:98007eb79fa8 474 close_destroy(close_performative);
AzureIoTClient 4:98007eb79fa8 475 }
Azure.IoT Build 0:6ae2f7bca550 476
AzureIoTClient 4:98007eb79fa8 477 return result;
Azure.IoT Build 0:6ae2f7bca550 478 }
Azure.IoT Build 0:6ae2f7bca550 479
AzureIoTClient 24:2c59c2d43ebf 480 static void close_connection_with_error(CONNECTION_HANDLE connection, const char* condition_value, const char* description)
Azure.IoT Build 0:6ae2f7bca550 481 {
AzureIoTClient 4:98007eb79fa8 482 ERROR_HANDLE error_handle = error_create(condition_value);
AzureIoTClient 4:98007eb79fa8 483 if (error_handle == NULL)
AzureIoTClient 4:98007eb79fa8 484 {
AzureIoTClient 4:98007eb79fa8 485 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 486 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 487 {
AzureIoTClient 28:add19eb7defa 488 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 489 }
AzureIoTClient 24:2c59c2d43ebf 490
AzureIoTClient 28:add19eb7defa 491 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 492 }
AzureIoTClient 4:98007eb79fa8 493 else
AzureIoTClient 4:98007eb79fa8 494 {
AzureIoTClient 4:98007eb79fa8 495 /* Codes_SRS_CONNECTION_01_219: [The error description shall be set to an implementation defined string.] */
AzureIoTClient 28:add19eb7defa 496 if (error_set_description(error_handle, description) != 0)
AzureIoTClient 28:add19eb7defa 497 {
AzureIoTClient 28:add19eb7defa 498 LogError("Cannot set error description on CLOSE frame");
AzureIoTClient 24:2c59c2d43ebf 499
AzureIoTClient 28:add19eb7defa 500 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 501 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 502 {
AzureIoTClient 28:add19eb7defa 503 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 504 }
AzureIoTClient 24:2c59c2d43ebf 505
AzureIoTClient 28:add19eb7defa 506 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 28:add19eb7defa 507 }
AzureIoTClient 28:add19eb7defa 508 else if (send_close_frame(connection, error_handle) != 0)
AzureIoTClient 28:add19eb7defa 509 {
AzureIoTClient 28:add19eb7defa 510 LogError("Cannot send CLOSE frame");
AzureIoTClient 24:2c59c2d43ebf 511
AzureIoTClient 28:add19eb7defa 512 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 513 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 514 {
AzureIoTClient 28:add19eb7defa 515 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 516 }
AzureIoTClient 24:2c59c2d43ebf 517
AzureIoTClient 24:2c59c2d43ebf 518 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 519 }
AzureIoTClient 4:98007eb79fa8 520 else
AzureIoTClient 4:98007eb79fa8 521 {
AzureIoTClient 4:98007eb79fa8 522 /* Codes_SRS_CONNECTION_01_213: [When passing the bytes to frame_codec fails, a CLOSE frame shall be sent and the state shall be set to DISCARDING.] */
AzureIoTClient 4:98007eb79fa8 523 /* Codes_SRS_CONNECTION_01_055: [DISCARDING The DISCARDING state is a variant of the CLOSE SENT state where the close is triggered by an error.] */
AzureIoTClient 16:22a72cf8e416 524 /* Codes_SRS_CONNECTION_01_010: [After writing this frame the peer SHOULD continue to read from the connection until it receives the partner's close frame ] */
AzureIoTClient 24:2c59c2d43ebf 525 connection_set_state(connection, CONNECTION_STATE_DISCARDING);
AzureIoTClient 4:98007eb79fa8 526 }
Azure.IoT Build 0:6ae2f7bca550 527
AzureIoTClient 4:98007eb79fa8 528 error_destroy(error_handle);
AzureIoTClient 4:98007eb79fa8 529 }
Azure.IoT Build 0:6ae2f7bca550 530 }
Azure.IoT Build 0:6ae2f7bca550 531
AzureIoTClient 24:2c59c2d43ebf 532 static ENDPOINT_INSTANCE* find_session_endpoint_by_outgoing_channel(CONNECTION_HANDLE connection, uint16_t outgoing_channel)
Azure.IoT Build 0:6ae2f7bca550 533 {
AzureIoTClient 4:98007eb79fa8 534 uint32_t i;
AzureIoTClient 4:98007eb79fa8 535 ENDPOINT_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 536
AzureIoTClient 4:98007eb79fa8 537 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 538 {
AzureIoTClient 4:98007eb79fa8 539 if (connection->endpoints[i]->outgoing_channel == outgoing_channel)
AzureIoTClient 4:98007eb79fa8 540 {
AzureIoTClient 4:98007eb79fa8 541 break;
AzureIoTClient 4:98007eb79fa8 542 }
AzureIoTClient 4:98007eb79fa8 543 }
Azure.IoT Build 0:6ae2f7bca550 544
AzureIoTClient 4:98007eb79fa8 545 if (i == connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 546 {
AzureIoTClient 28:add19eb7defa 547 LogError("Cannot find session endpoint for channel %u", (unsigned int)outgoing_channel);
AzureIoTClient 28:add19eb7defa 548 result = NULL;
AzureIoTClient 4:98007eb79fa8 549 }
AzureIoTClient 4:98007eb79fa8 550 else
AzureIoTClient 4:98007eb79fa8 551 {
AzureIoTClient 4:98007eb79fa8 552 result = connection->endpoints[i];
AzureIoTClient 4:98007eb79fa8 553 }
Azure.IoT Build 0:6ae2f7bca550 554
AzureIoTClient 4:98007eb79fa8 555 return result;
Azure.IoT Build 0:6ae2f7bca550 556 }
Azure.IoT Build 0:6ae2f7bca550 557
AzureIoTClient 24:2c59c2d43ebf 558 static ENDPOINT_INSTANCE* find_session_endpoint_by_incoming_channel(CONNECTION_HANDLE connection, uint16_t incoming_channel)
Azure.IoT Build 0:6ae2f7bca550 559 {
AzureIoTClient 4:98007eb79fa8 560 uint32_t i;
AzureIoTClient 4:98007eb79fa8 561 ENDPOINT_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 562
AzureIoTClient 4:98007eb79fa8 563 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 564 {
AzureIoTClient 4:98007eb79fa8 565 if (connection->endpoints[i]->incoming_channel == incoming_channel)
AzureIoTClient 4:98007eb79fa8 566 {
AzureIoTClient 4:98007eb79fa8 567 break;
AzureIoTClient 4:98007eb79fa8 568 }
AzureIoTClient 4:98007eb79fa8 569 }
Azure.IoT Build 0:6ae2f7bca550 570
AzureIoTClient 4:98007eb79fa8 571 if (i == connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 572 {
AzureIoTClient 28:add19eb7defa 573 LogError("Cannot find session endpoint for channel %u", (unsigned int)incoming_channel);
AzureIoTClient 28:add19eb7defa 574 result = NULL;
AzureIoTClient 4:98007eb79fa8 575 }
AzureIoTClient 4:98007eb79fa8 576 else
AzureIoTClient 4:98007eb79fa8 577 {
AzureIoTClient 4:98007eb79fa8 578 result = connection->endpoints[i];
AzureIoTClient 4:98007eb79fa8 579 }
Azure.IoT Build 0:6ae2f7bca550 580
AzureIoTClient 4:98007eb79fa8 581 return result;
Azure.IoT Build 0:6ae2f7bca550 582 }
Azure.IoT Build 0:6ae2f7bca550 583
AzureIoTClient 24:2c59c2d43ebf 584 static int connection_byte_received(CONNECTION_HANDLE connection, unsigned char b)
Azure.IoT Build 0:6ae2f7bca550 585 {
AzureIoTClient 4:98007eb79fa8 586 int result;
Azure.IoT Build 0:6ae2f7bca550 587
AzureIoTClient 24:2c59c2d43ebf 588 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 589 {
AzureIoTClient 4:98007eb79fa8 590 default:
AzureIoTClient 28:add19eb7defa 591 LogError("Unknown connection state: %d", (int)connection->connection_state);
AzureIoTClient 28:add19eb7defa 592 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 593 break;
Azure.IoT Build 0:6ae2f7bca550 594
AzureIoTClient 4:98007eb79fa8 595 /* Codes_SRS_CONNECTION_01_039: [START In this state a connection exists, but nothing has been sent or received. This is the state an implementation would be in immediately after performing a socket connect or socket accept.] */
AzureIoTClient 4:98007eb79fa8 596 case CONNECTION_STATE_START:
Azure.IoT Build 0:6ae2f7bca550 597
AzureIoTClient 4:98007eb79fa8 598 /* Codes_SRS_CONNECTION_01_041: [HDR SENT In this state the connection header has been sent to the peer but no connection header has been received.] */
AzureIoTClient 4:98007eb79fa8 599 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 24:2c59c2d43ebf 600 if (b != amqp_header[connection->header_bytes_received])
AzureIoTClient 4:98007eb79fa8 601 {
AzureIoTClient 4:98007eb79fa8 602 /* Codes_SRS_CONNECTION_01_089: [If the incoming and outgoing protocol headers do not match, both peers MUST close their outgoing stream] */
AzureIoTClient 28:add19eb7defa 603 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 604 {
AzureIoTClient 28:add19eb7defa 605 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 606 }
AzureIoTClient 24:2c59c2d43ebf 607
AzureIoTClient 28:add19eb7defa 608 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 609 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 610 }
AzureIoTClient 4:98007eb79fa8 611 else
AzureIoTClient 4:98007eb79fa8 612 {
AzureIoTClient 28:add19eb7defa 613 connection->header_bytes_received++;
AzureIoTClient 24:2c59c2d43ebf 614 if (connection->header_bytes_received == sizeof(amqp_header))
AzureIoTClient 4:98007eb79fa8 615 {
AzureIoTClient 24:2c59c2d43ebf 616 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 617 {
AzureIoTClient 16:22a72cf8e416 618 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Header (AMQP 0.1.0.0)");
AzureIoTClient 4:98007eb79fa8 619 }
Azure.IoT Build 0:6ae2f7bca550 620
AzureIoTClient 24:2c59c2d43ebf 621 connection_set_state(connection, CONNECTION_STATE_HDR_EXCH);
Azure.IoT Build 0:6ae2f7bca550 622
AzureIoTClient 24:2c59c2d43ebf 623 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 624 {
AzureIoTClient 28:add19eb7defa 625 LogError("Cannot send open frame");
AzureIoTClient 28:add19eb7defa 626 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 627 }
AzureIoTClient 4:98007eb79fa8 628 }
Azure.IoT Build 0:6ae2f7bca550 629
AzureIoTClient 4:98007eb79fa8 630 result = 0;
AzureIoTClient 4:98007eb79fa8 631 }
AzureIoTClient 4:98007eb79fa8 632 break;
Azure.IoT Build 0:6ae2f7bca550 633
AzureIoTClient 4:98007eb79fa8 634 /* Codes_SRS_CONNECTION_01_040: [HDR RCVD In this state the connection header has been received from the peer but a connection header has not been sent.] */
AzureIoTClient 4:98007eb79fa8 635 case CONNECTION_STATE_HDR_RCVD:
Azure.IoT Build 0:6ae2f7bca550 636
AzureIoTClient 4:98007eb79fa8 637 /* Codes_SRS_CONNECTION_01_042: [HDR EXCH In this state the connection header has been sent to the peer and a connection header has been received from the peer.] */
AzureIoTClient 4:98007eb79fa8 638 /* we should not really get into this state, but just in case, we would treat that in the same way as HDR_RCVD */
AzureIoTClient 4:98007eb79fa8 639 case CONNECTION_STATE_HDR_EXCH:
Azure.IoT Build 0:6ae2f7bca550 640
AzureIoTClient 4:98007eb79fa8 641 /* Codes_SRS_CONNECTION_01_045: [OPEN RCVD In this state the connection headers have been exchanged. An open frame has been received from the peer but an open frame has not been sent.] */
AzureIoTClient 4:98007eb79fa8 642 case CONNECTION_STATE_OPEN_RCVD:
Azure.IoT Build 0:6ae2f7bca550 643
AzureIoTClient 4:98007eb79fa8 644 /* Codes_SRS_CONNECTION_01_046: [OPEN SENT In this state the connection headers have been exchanged. An open frame has been sent to the peer but no open frame has yet been received.] */
AzureIoTClient 4:98007eb79fa8 645 case CONNECTION_STATE_OPEN_SENT:
Azure.IoT Build 0:6ae2f7bca550 646
AzureIoTClient 4:98007eb79fa8 647 /* Codes_SRS_CONNECTION_01_048: [OPENED In this state the connection header and the open frame have been both sent and received.] */
AzureIoTClient 4:98007eb79fa8 648 case CONNECTION_STATE_OPENED:
AzureIoTClient 4:98007eb79fa8 649 /* Codes_SRS_CONNECTION_01_212: [After the initial handshake has been done all bytes received from the io instance shall be passed to the frame_codec for decoding by calling frame_codec_receive_bytes.] */
AzureIoTClient 24:2c59c2d43ebf 650 if (frame_codec_receive_bytes(connection->frame_codec, &b, 1) != 0)
AzureIoTClient 4:98007eb79fa8 651 {
AzureIoTClient 28:add19eb7defa 652 LogError("Cannot process received bytes");
AzureIoTClient 28:add19eb7defa 653 /* Codes_SRS_CONNECTION_01_218: [The error amqp:internal-error shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 4:98007eb79fa8 654 /* Codes_SRS_CONNECTION_01_219: [The error description shall be set to an implementation defined string.] */
AzureIoTClient 24:2c59c2d43ebf 655 close_connection_with_error(connection, "amqp:internal-error", "connection_byte_received::frame_codec_receive_bytes failed");
AzureIoTClient 19:000ab4e6a2c1 656 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 657 }
AzureIoTClient 4:98007eb79fa8 658 else
AzureIoTClient 4:98007eb79fa8 659 {
AzureIoTClient 4:98007eb79fa8 660 result = 0;
AzureIoTClient 4:98007eb79fa8 661 }
Azure.IoT Build 0:6ae2f7bca550 662
AzureIoTClient 4:98007eb79fa8 663 break;
AzureIoTClient 4:98007eb79fa8 664 }
AzureIoTClient 4:98007eb79fa8 665
AzureIoTClient 4:98007eb79fa8 666 return result;
Azure.IoT Build 0:6ae2f7bca550 667 }
Azure.IoT Build 0:6ae2f7bca550 668
Azure.IoT Build 0:6ae2f7bca550 669 static void connection_on_bytes_received(void* context, const unsigned char* buffer, size_t size)
Azure.IoT Build 0:6ae2f7bca550 670 {
AzureIoTClient 4:98007eb79fa8 671 size_t i;
Azure.IoT Build 0:6ae2f7bca550 672
AzureIoTClient 4:98007eb79fa8 673 for (i = 0; i < size; i++)
AzureIoTClient 4:98007eb79fa8 674 {
AzureIoTClient 24:2c59c2d43ebf 675 if (connection_byte_received((CONNECTION_HANDLE)context, buffer[i]) != 0)
AzureIoTClient 4:98007eb79fa8 676 {
AzureIoTClient 28:add19eb7defa 677 LogError("Cannot process received bytes");
AzureIoTClient 28:add19eb7defa 678 break;
AzureIoTClient 4:98007eb79fa8 679 }
AzureIoTClient 4:98007eb79fa8 680 }
Azure.IoT Build 0:6ae2f7bca550 681 }
Azure.IoT Build 0:6ae2f7bca550 682
Azure.IoT Build 0:6ae2f7bca550 683 static void connection_on_io_open_complete(void* context, IO_OPEN_RESULT io_open_result)
Azure.IoT Build 0:6ae2f7bca550 684 {
AzureIoTClient 24:2c59c2d43ebf 685 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
Azure.IoT Build 0:6ae2f7bca550 686
AzureIoTClient 4:98007eb79fa8 687 if (io_open_result == IO_OPEN_OK)
AzureIoTClient 4:98007eb79fa8 688 {
AzureIoTClient 4:98007eb79fa8 689 /* Codes_SRS_CONNECTION_01_084: [The connection_instance state machine implementing the protocol requirements shall be run as part of connection_dowork.] */
AzureIoTClient 24:2c59c2d43ebf 690 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 691 {
AzureIoTClient 4:98007eb79fa8 692 default:
AzureIoTClient 28:add19eb7defa 693 LogError("Unknown connection state: %d", (int)connection->connection_state);
AzureIoTClient 28:add19eb7defa 694 break;
Azure.IoT Build 0:6ae2f7bca550 695
AzureIoTClient 4:98007eb79fa8 696 case CONNECTION_STATE_START:
AzureIoTClient 4:98007eb79fa8 697 /* Codes_SRS_CONNECTION_01_086: [Prior to sending any frames on a connection_instance, each peer MUST start by sending a protocol header that indicates the protocol version used on the connection_instance.] */
AzureIoTClient 4:98007eb79fa8 698 /* Codes_SRS_CONNECTION_01_091: [The AMQP peer which acted in the role of the TCP client (i.e. the peer that actively opened the connection_instance) MUST immediately send its outgoing protocol header on establishment of the TCP connection_instance.] */
AzureIoTClient 28:add19eb7defa 699 if (send_header(connection) != 0)
AzureIoTClient 28:add19eb7defa 700 {
AzureIoTClient 28:add19eb7defa 701 LogError("Cannot send header");
AzureIoTClient 28:add19eb7defa 702 }
AzureIoTClient 4:98007eb79fa8 703 break;
Azure.IoT Build 0:6ae2f7bca550 704
AzureIoTClient 4:98007eb79fa8 705 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 4:98007eb79fa8 706 case CONNECTION_STATE_OPEN_SENT:
AzureIoTClient 4:98007eb79fa8 707 case CONNECTION_STATE_OPENED:
AzureIoTClient 4:98007eb79fa8 708 break;
Azure.IoT Build 0:6ae2f7bca550 709
AzureIoTClient 4:98007eb79fa8 710 case CONNECTION_STATE_HDR_EXCH:
AzureIoTClient 4:98007eb79fa8 711 /* Codes_SRS_CONNECTION_01_002: [Each AMQP connection_instance begins with an exchange of capabilities and limitations, including the maximum frame size.] */
AzureIoTClient 4:98007eb79fa8 712 /* Codes_SRS_CONNECTION_01_004: [After establishing or accepting a TCP connection_instance and sending the protocol header, each peer MUST send an open frame before sending any other frames.] */
AzureIoTClient 4:98007eb79fa8 713 /* Codes_SRS_CONNECTION_01_005: [The open frame describes the capabilities and limits of that peer.] */
AzureIoTClient 24:2c59c2d43ebf 714 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 715 {
AzureIoTClient 28:add19eb7defa 716 LogError("Cannot send OPEN frame");
AzureIoTClient 28:add19eb7defa 717 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 718 }
AzureIoTClient 4:98007eb79fa8 719 break;
Azure.IoT Build 0:6ae2f7bca550 720
AzureIoTClient 4:98007eb79fa8 721 case CONNECTION_STATE_OPEN_RCVD:
AzureIoTClient 4:98007eb79fa8 722 break;
AzureIoTClient 4:98007eb79fa8 723 }
AzureIoTClient 4:98007eb79fa8 724 }
AzureIoTClient 4:98007eb79fa8 725 else
AzureIoTClient 4:98007eb79fa8 726 {
AzureIoTClient 24:2c59c2d43ebf 727 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 728 }
Azure.IoT Build 0:6ae2f7bca550 729 }
Azure.IoT Build 0:6ae2f7bca550 730
Azure.IoT Build 0:6ae2f7bca550 731 static void connection_on_io_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 732 {
AzureIoTClient 28:add19eb7defa 733 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
Azure.IoT Build 0:6ae2f7bca550 734
Azure.IoT Build 0:6ae2f7bca550 735 /* Codes_SRS_CONNECTION_22_005: [If the io notifies the connection instance of an IO_STATE_ERROR state and an io error callback is registered, the connection shall call the registered callback.] */
AzureIoTClient 24:2c59c2d43ebf 736 if (connection->on_io_error)
Azure.IoT Build 0:6ae2f7bca550 737 {
AzureIoTClient 28:add19eb7defa 738 connection->on_io_error(connection->on_io_error_callback_context);
Azure.IoT Build 0:6ae2f7bca550 739 }
Azure.IoT Build 0:6ae2f7bca550 740
AzureIoTClient 24:2c59c2d43ebf 741 if (connection->connection_state != CONNECTION_STATE_END)
AzureIoTClient 4:98007eb79fa8 742 {
AzureIoTClient 4:98007eb79fa8 743 /* Codes_SRS_CONNECTION_01_202: [If the io notifies the connection instance of an IO_STATE_ERROR state the connection shall be closed and the state set to END.] */
AzureIoTClient 24:2c59c2d43ebf 744 connection_set_state(connection, CONNECTION_STATE_ERROR);
AzureIoTClient 28:add19eb7defa 745 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 746 {
AzureIoTClient 28:add19eb7defa 747 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 748 }
AzureIoTClient 28:add19eb7defa 749 }
Azure.IoT Build 0:6ae2f7bca550 750 }
Azure.IoT Build 0:6ae2f7bca550 751
Azure.IoT Build 0:6ae2f7bca550 752 static void on_empty_amqp_frame_received(void* context, uint16_t channel)
Azure.IoT Build 0:6ae2f7bca550 753 {
AzureIoTClient 28:add19eb7defa 754 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 28:add19eb7defa 755 /* It does not matter on which channel we received the frame */
AzureIoTClient 28:add19eb7defa 756 (void)channel;
AzureIoTClient 24:2c59c2d43ebf 757
AzureIoTClient 28:add19eb7defa 758 if (connection->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 759 {
AzureIoTClient 16:22a72cf8e416 760 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Empty frame");
AzureIoTClient 6:641a9672db08 761 }
AzureIoTClient 24:2c59c2d43ebf 762 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 4:98007eb79fa8 763 {
AzureIoTClient 28:add19eb7defa 764 LogError("Cannot get tickcounter value");
AzureIoTClient 28:add19eb7defa 765 }
Azure.IoT Build 0:6ae2f7bca550 766 }
Azure.IoT Build 0:6ae2f7bca550 767
Azure.IoT Build 0:6ae2f7bca550 768 static void on_amqp_frame_received(void* context, uint16_t channel, AMQP_VALUE performative, const unsigned char* payload_bytes, uint32_t payload_size)
Azure.IoT Build 0:6ae2f7bca550 769 {
AzureIoTClient 24:2c59c2d43ebf 770 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 24:2c59c2d43ebf 771
AzureIoTClient 28:add19eb7defa 772 (void)channel;
Azure.IoT Build 0:6ae2f7bca550 773
AzureIoTClient 24:2c59c2d43ebf 774 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 4:98007eb79fa8 775 {
AzureIoTClient 28:add19eb7defa 776 LogError("Cannot get tickcounter value");
AzureIoTClient 28:add19eb7defa 777 close_connection_with_error(connection, "amqp:internal-error", "cannot get current tick count");
AzureIoTClient 4:98007eb79fa8 778 }
AzureIoTClient 4:98007eb79fa8 779 else
AzureIoTClient 4:98007eb79fa8 780 {
AzureIoTClient 24:2c59c2d43ebf 781 if (connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 782 {
AzureIoTClient 24:2c59c2d43ebf 783 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 784 {
AzureIoTClient 4:98007eb79fa8 785 default:
AzureIoTClient 4:98007eb79fa8 786 if (performative == NULL)
AzureIoTClient 4:98007eb79fa8 787 {
AzureIoTClient 28:add19eb7defa 788 /* Codes_SRS_CONNECTION_01_223: [If the on_endpoint_frame_received is called with a NULL performative then the connection shall be closed with the error condition amqp:internal-error and an implementation defined error description.] */
AzureIoTClient 24:2c59c2d43ebf 789 close_connection_with_error(connection, "amqp:internal-error", "connection_endpoint_frame_received::NULL performative");
AzureIoTClient 28:add19eb7defa 790 LogError("connection_endpoint_frame_received::NULL performative");
AzureIoTClient 28:add19eb7defa 791 }
AzureIoTClient 4:98007eb79fa8 792 else
AzureIoTClient 4:98007eb79fa8 793 {
AzureIoTClient 4:98007eb79fa8 794 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 4:98007eb79fa8 795 uint64_t performative_ulong;
Azure.IoT Build 0:6ae2f7bca550 796
AzureIoTClient 24:2c59c2d43ebf 797 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 798 {
Azure.IoT Build 5:ae49385aff34 799 log_incoming_frame(performative);
AzureIoTClient 4:98007eb79fa8 800 }
Azure.IoT Build 0:6ae2f7bca550 801
AzureIoTClient 4:98007eb79fa8 802 if (is_open_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 803 {
AzureIoTClient 4:98007eb79fa8 804 if (channel != 0)
AzureIoTClient 4:98007eb79fa8 805 {
AzureIoTClient 28:add19eb7defa 806 /* Codes_SRS_CONNECTION_01_006: [The open frame can only be sent on channel 0.] */
AzureIoTClient 4:98007eb79fa8 807 /* Codes_SRS_CONNECTION_01_222: [If an Open frame is received in a manner violating the ISO specification, the connection shall be closed with condition amqp:not-allowed and description being an implementation defined string.] */
AzureIoTClient 24:2c59c2d43ebf 808 close_connection_with_error(connection, "amqp:not-allowed", "OPEN frame received on a channel that is not 0");
AzureIoTClient 28:add19eb7defa 809 LogError("OPEN frame received on a channel that is not 0");
AzureIoTClient 28:add19eb7defa 810 }
Azure.IoT Build 0:6ae2f7bca550 811
AzureIoTClient 24:2c59c2d43ebf 812 if (connection->connection_state == CONNECTION_STATE_OPENED)
AzureIoTClient 4:98007eb79fa8 813 {
AzureIoTClient 4:98007eb79fa8 814 /* Codes_SRS_CONNECTION_01_239: [If an Open frame is received in the Opened state the connection shall be closed with condition amqp:illegal-state and description being an implementation defined string.] */
AzureIoTClient 24:2c59c2d43ebf 815 close_connection_with_error(connection, "amqp:illegal-state", "OPEN frame received in the OPENED state");
AzureIoTClient 28:add19eb7defa 816 LogError("OPEN frame received in the OPENED state");
AzureIoTClient 28:add19eb7defa 817 }
AzureIoTClient 24:2c59c2d43ebf 818 else if ((connection->connection_state == CONNECTION_STATE_OPEN_SENT) ||
AzureIoTClient 24:2c59c2d43ebf 819 (connection->connection_state == CONNECTION_STATE_HDR_EXCH))
AzureIoTClient 4:98007eb79fa8 820 {
AzureIoTClient 4:98007eb79fa8 821 OPEN_HANDLE open_handle;
AzureIoTClient 4:98007eb79fa8 822 if (amqpvalue_get_open(performative, &open_handle) != 0)
AzureIoTClient 4:98007eb79fa8 823 {
AzureIoTClient 4:98007eb79fa8 824 /* Codes_SRS_CONNECTION_01_143: [If any of the values in the received open frame are invalid then the connection shall be closed.] */
AzureIoTClient 4:98007eb79fa8 825 /* Codes_SRS_CONNECTION_01_220: [The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 24:2c59c2d43ebf 826 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 827 LogError("connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 828 }
AzureIoTClient 4:98007eb79fa8 829 else
AzureIoTClient 4:98007eb79fa8 830 {
AzureIoTClient 35:d0bed2404ee9 831 if (open_get_idle_time_out(open_handle, &connection->remote_idle_timeout) == 0)
AzureIoTClient 35:d0bed2404ee9 832 {
AzureIoTClient 35:d0bed2404ee9 833 /* since we obtained the remote_idle_timeout, compute at what millisecond we should send the empty frame */
AzureIoTClient 35:d0bed2404ee9 834 connection->remote_idle_timeout_send_frame_millisecond = (milliseconds)(connection->idle_timeout_empty_frame_send_ratio * connection->remote_idle_timeout);
AzureIoTClient 35:d0bed2404ee9 835 }
AzureIoTClient 35:d0bed2404ee9 836
AzureIoTClient 24:2c59c2d43ebf 837 if ((open_get_max_frame_size(open_handle, &connection->remote_max_frame_size) != 0) ||
AzureIoTClient 4:98007eb79fa8 838 /* Codes_SRS_CONNECTION_01_167: [Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.] */
AzureIoTClient 24:2c59c2d43ebf 839 (connection->remote_max_frame_size < 512))
AzureIoTClient 4:98007eb79fa8 840 {
AzureIoTClient 4:98007eb79fa8 841 /* Codes_SRS_CONNECTION_01_143: [If any of the values in the received open frame are invalid then the connection shall be closed.] */
AzureIoTClient 4:98007eb79fa8 842 /* Codes_SRS_CONNECTION_01_220: [The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 24:2c59c2d43ebf 843 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 844 LogError("connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 845 }
AzureIoTClient 4:98007eb79fa8 846 else
AzureIoTClient 4:98007eb79fa8 847 {
AzureIoTClient 24:2c59c2d43ebf 848 if (connection->connection_state == CONNECTION_STATE_OPEN_SENT)
AzureIoTClient 4:98007eb79fa8 849 {
AzureIoTClient 24:2c59c2d43ebf 850 connection_set_state(connection, CONNECTION_STATE_OPENED);
AzureIoTClient 4:98007eb79fa8 851 }
AzureIoTClient 4:98007eb79fa8 852 else
AzureIoTClient 4:98007eb79fa8 853 {
AzureIoTClient 24:2c59c2d43ebf 854 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 855 {
AzureIoTClient 24:2c59c2d43ebf 856 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 857 }
AzureIoTClient 4:98007eb79fa8 858 else
AzureIoTClient 4:98007eb79fa8 859 {
AzureIoTClient 24:2c59c2d43ebf 860 connection_set_state(connection, CONNECTION_STATE_OPENED);
AzureIoTClient 4:98007eb79fa8 861 }
AzureIoTClient 4:98007eb79fa8 862 }
AzureIoTClient 4:98007eb79fa8 863 }
Azure.IoT Build 0:6ae2f7bca550 864
AzureIoTClient 4:98007eb79fa8 865 open_destroy(open_handle);
AzureIoTClient 4:98007eb79fa8 866 }
AzureIoTClient 4:98007eb79fa8 867 }
AzureIoTClient 4:98007eb79fa8 868 else
AzureIoTClient 4:98007eb79fa8 869 {
AzureIoTClient 4:98007eb79fa8 870 /* do nothing for now ... */
AzureIoTClient 4:98007eb79fa8 871 }
AzureIoTClient 4:98007eb79fa8 872 }
AzureIoTClient 4:98007eb79fa8 873 else if (is_close_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 874 {
AzureIoTClient 4:98007eb79fa8 875 /* Codes_SRS_CONNECTION_01_012: [A close frame MAY be received on any channel up to the maximum channel number negotiated in open.] */
AzureIoTClient 4:98007eb79fa8 876 /* Codes_SRS_CONNECTION_01_242: [The connection module shall accept CLOSE frames even if they have extra payload bytes besides the Close performative.] */
Azure.IoT Build 0:6ae2f7bca550 877
AzureIoTClient 4:98007eb79fa8 878 /* Codes_SRS_CONNECTION_01_225: [HDR_RCVD HDR OPEN] */
AzureIoTClient 24:2c59c2d43ebf 879 if ((connection->connection_state == CONNECTION_STATE_HDR_RCVD) ||
AzureIoTClient 4:98007eb79fa8 880 /* Codes_SRS_CONNECTION_01_227: [HDR_EXCH OPEN OPEN] */
AzureIoTClient 24:2c59c2d43ebf 881 (connection->connection_state == CONNECTION_STATE_HDR_EXCH) ||
AzureIoTClient 4:98007eb79fa8 882 /* Codes_SRS_CONNECTION_01_228: [OPEN_RCVD OPEN *] */
AzureIoTClient 24:2c59c2d43ebf 883 (connection->connection_state == CONNECTION_STATE_OPEN_RCVD) ||
AzureIoTClient 4:98007eb79fa8 884 /* Codes_SRS_CONNECTION_01_235: [CLOSE_SENT - * TCP Close for Write] */
AzureIoTClient 24:2c59c2d43ebf 885 (connection->connection_state == CONNECTION_STATE_CLOSE_SENT) ||
AzureIoTClient 4:98007eb79fa8 886 /* Codes_SRS_CONNECTION_01_236: [DISCARDING - * TCP Close for Write] */
AzureIoTClient 24:2c59c2d43ebf 887 (connection->connection_state == CONNECTION_STATE_DISCARDING))
AzureIoTClient 4:98007eb79fa8 888 {
AzureIoTClient 28:add19eb7defa 889 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 890 {
AzureIoTClient 28:add19eb7defa 891 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 892 }
AzureIoTClient 28:add19eb7defa 893 }
AzureIoTClient 4:98007eb79fa8 894 else
AzureIoTClient 4:98007eb79fa8 895 {
AzureIoTClient 4:98007eb79fa8 896 CLOSE_HANDLE close_handle;
Azure.IoT Build 0:6ae2f7bca550 897
AzureIoTClient 4:98007eb79fa8 898 /* Codes_SRS_CONNECTION_01_012: [A close frame MAY be received on any channel up to the maximum channel number negotiated in open.] */
AzureIoTClient 24:2c59c2d43ebf 899 if (channel > connection->channel_max)
AzureIoTClient 4:98007eb79fa8 900 {
AzureIoTClient 24:2c59c2d43ebf 901 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 902 LogError("connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 903 }
AzureIoTClient 4:98007eb79fa8 904 else
AzureIoTClient 4:98007eb79fa8 905 {
AzureIoTClient 4:98007eb79fa8 906 if (amqpvalue_get_close(performative, &close_handle) != 0)
AzureIoTClient 4:98007eb79fa8 907 {
AzureIoTClient 24:2c59c2d43ebf 908 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 909 LogError("connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 910 }
AzureIoTClient 4:98007eb79fa8 911 else
AzureIoTClient 4:98007eb79fa8 912 {
AzureIoTClient 4:98007eb79fa8 913 close_destroy(close_handle);
Azure.IoT Build 0:6ae2f7bca550 914
AzureIoTClient 24:2c59c2d43ebf 915 connection_set_state(connection, CONNECTION_STATE_CLOSE_RCVD);
Azure.IoT Build 0:6ae2f7bca550 916
AzureIoTClient 28:add19eb7defa 917 if (send_close_frame(connection, NULL) != 0)
AzureIoTClient 28:add19eb7defa 918 {
AzureIoTClient 28:add19eb7defa 919 LogError("Cannot send CLOSE frame");
AzureIoTClient 28:add19eb7defa 920 }
AzureIoTClient 24:2c59c2d43ebf 921
AzureIoTClient 4:98007eb79fa8 922 /* Codes_SRS_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 923 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 924 {
AzureIoTClient 28:add19eb7defa 925 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 926 }
Azure.IoT Build 0:6ae2f7bca550 927
AzureIoTClient 24:2c59c2d43ebf 928 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 929 }
AzureIoTClient 4:98007eb79fa8 930 }
AzureIoTClient 4:98007eb79fa8 931 }
AzureIoTClient 4:98007eb79fa8 932 }
AzureIoTClient 4:98007eb79fa8 933 else
AzureIoTClient 4:98007eb79fa8 934 {
AzureIoTClient 4:98007eb79fa8 935 amqpvalue_get_ulong(descriptor, &performative_ulong);
Azure.IoT Build 0:6ae2f7bca550 936
AzureIoTClient 4:98007eb79fa8 937 switch (performative_ulong)
AzureIoTClient 4:98007eb79fa8 938 {
AzureIoTClient 4:98007eb79fa8 939 default:
AzureIoTClient 28:add19eb7defa 940 LogError("Bad performative: %02x", performative);
AzureIoTClient 4:98007eb79fa8 941 break;
Azure.IoT Build 0:6ae2f7bca550 942
AzureIoTClient 4:98007eb79fa8 943 case AMQP_BEGIN:
AzureIoTClient 4:98007eb79fa8 944 {
AzureIoTClient 4:98007eb79fa8 945 BEGIN_HANDLE begin;
Azure.IoT Build 0:6ae2f7bca550 946
AzureIoTClient 24:2c59c2d43ebf 947 if (amqpvalue_get_begin(performative, &begin) != 0)
AzureIoTClient 4:98007eb79fa8 948 {
AzureIoTClient 28:add19eb7defa 949 LogError("Cannot get begin performative");
AzureIoTClient 28:add19eb7defa 950 }
AzureIoTClient 4:98007eb79fa8 951 else
AzureIoTClient 4:98007eb79fa8 952 {
AzureIoTClient 4:98007eb79fa8 953 uint16_t remote_channel;
AzureIoTClient 4:98007eb79fa8 954 ENDPOINT_HANDLE new_endpoint = NULL;
AzureIoTClient 4:98007eb79fa8 955 bool remote_begin = false;
Azure.IoT Build 0:6ae2f7bca550 956
AzureIoTClient 4:98007eb79fa8 957 if (begin_get_remote_channel(begin, &remote_channel) != 0)
AzureIoTClient 4:98007eb79fa8 958 {
AzureIoTClient 28:add19eb7defa 959 remote_begin = true;
AzureIoTClient 24:2c59c2d43ebf 960 if (connection->on_new_endpoint != NULL)
AzureIoTClient 4:98007eb79fa8 961 {
AzureIoTClient 24:2c59c2d43ebf 962 new_endpoint = connection_create_endpoint(connection);
AzureIoTClient 24:2c59c2d43ebf 963 if (!connection->on_new_endpoint(connection->on_new_endpoint_callback_context, new_endpoint))
AzureIoTClient 4:98007eb79fa8 964 {
AzureIoTClient 4:98007eb79fa8 965 connection_destroy_endpoint(new_endpoint);
AzureIoTClient 4:98007eb79fa8 966 new_endpoint = NULL;
AzureIoTClient 4:98007eb79fa8 967 }
AzureIoTClient 4:98007eb79fa8 968 }
AzureIoTClient 4:98007eb79fa8 969 }
Azure.IoT Build 0:6ae2f7bca550 970
AzureIoTClient 4:98007eb79fa8 971 if (!remote_begin)
AzureIoTClient 4:98007eb79fa8 972 {
AzureIoTClient 24:2c59c2d43ebf 973 ENDPOINT_INSTANCE* session_endpoint = find_session_endpoint_by_outgoing_channel(connection, remote_channel);
AzureIoTClient 4:98007eb79fa8 974 if (session_endpoint == NULL)
AzureIoTClient 4:98007eb79fa8 975 {
AzureIoTClient 28:add19eb7defa 976 LogError("Cannot create session endpoint");
AzureIoTClient 28:add19eb7defa 977 }
AzureIoTClient 4:98007eb79fa8 978 else
AzureIoTClient 4:98007eb79fa8 979 {
AzureIoTClient 4:98007eb79fa8 980 session_endpoint->incoming_channel = channel;
AzureIoTClient 4:98007eb79fa8 981 session_endpoint->on_endpoint_frame_received(session_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 4:98007eb79fa8 982 }
AzureIoTClient 4:98007eb79fa8 983 }
AzureIoTClient 4:98007eb79fa8 984 else
AzureIoTClient 4:98007eb79fa8 985 {
Azure.IoT Build 0:6ae2f7bca550 986 if (new_endpoint != NULL)
Azure.IoT Build 0:6ae2f7bca550 987 {
Azure.IoT Build 0:6ae2f7bca550 988 new_endpoint->incoming_channel = channel;
Azure.IoT Build 0:6ae2f7bca550 989 new_endpoint->on_endpoint_frame_received(new_endpoint->callback_context, performative, payload_size, payload_bytes);
Azure.IoT Build 0:6ae2f7bca550 990 }
AzureIoTClient 4:98007eb79fa8 991 }
Azure.IoT Build 0:6ae2f7bca550 992
AzureIoTClient 4:98007eb79fa8 993 begin_destroy(begin);
AzureIoTClient 4:98007eb79fa8 994 }
Azure.IoT Build 0:6ae2f7bca550 995
AzureIoTClient 4:98007eb79fa8 996 break;
AzureIoTClient 4:98007eb79fa8 997 }
Azure.IoT Build 0:6ae2f7bca550 998
AzureIoTClient 4:98007eb79fa8 999 case AMQP_FLOW:
AzureIoTClient 4:98007eb79fa8 1000 case AMQP_TRANSFER:
AzureIoTClient 4:98007eb79fa8 1001 case AMQP_DISPOSITION:
AzureIoTClient 4:98007eb79fa8 1002 case AMQP_END:
AzureIoTClient 4:98007eb79fa8 1003 case AMQP_ATTACH:
AzureIoTClient 4:98007eb79fa8 1004 case AMQP_DETACH:
AzureIoTClient 4:98007eb79fa8 1005 {
AzureIoTClient 24:2c59c2d43ebf 1006 ENDPOINT_INSTANCE* session_endpoint = find_session_endpoint_by_incoming_channel(connection, channel);
AzureIoTClient 4:98007eb79fa8 1007 if (session_endpoint == NULL)
AzureIoTClient 4:98007eb79fa8 1008 {
AzureIoTClient 28:add19eb7defa 1009 LogError("Cannot find session endpoint for channel %u", (unsigned int)channel);
AzureIoTClient 28:add19eb7defa 1010 }
AzureIoTClient 4:98007eb79fa8 1011 else
AzureIoTClient 4:98007eb79fa8 1012 {
AzureIoTClient 4:98007eb79fa8 1013 session_endpoint->on_endpoint_frame_received(session_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 4:98007eb79fa8 1014 }
Azure.IoT Build 0:6ae2f7bca550 1015
AzureIoTClient 4:98007eb79fa8 1016 break;
AzureIoTClient 4:98007eb79fa8 1017 }
AzureIoTClient 4:98007eb79fa8 1018 }
AzureIoTClient 4:98007eb79fa8 1019 }
AzureIoTClient 4:98007eb79fa8 1020 }
AzureIoTClient 4:98007eb79fa8 1021 break;
Azure.IoT Build 0:6ae2f7bca550 1022
AzureIoTClient 4:98007eb79fa8 1023 case CONNECTION_STATE_START:
AzureIoTClient 4:98007eb79fa8 1024 /* Codes_SRS_CONNECTION_01_224: [START HDR HDR] */
AzureIoTClient 4:98007eb79fa8 1025 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 4:98007eb79fa8 1026 /* Codes_SRS_CONNECTION_01_226: [HDR_SENT OPEN HDR] */
AzureIoTClient 4:98007eb79fa8 1027 case CONNECTION_STATE_OPEN_PIPE:
AzureIoTClient 4:98007eb79fa8 1028 /* Codes_SRS_CONNECTION_01_230: [OPEN_PIPE ** HDR] */
AzureIoTClient 4:98007eb79fa8 1029 case CONNECTION_STATE_OC_PIPE:
AzureIoTClient 4:98007eb79fa8 1030 /* Codes_SRS_CONNECTION_01_232: [OC_PIPE - HDR TCP Close for Write] */
AzureIoTClient 4:98007eb79fa8 1031 case CONNECTION_STATE_CLOSE_RCVD:
AzureIoTClient 4:98007eb79fa8 1032 /* Codes_SRS_CONNECTION_01_234: [CLOSE_RCVD * - TCP Close for Read] */
AzureIoTClient 4:98007eb79fa8 1033 case CONNECTION_STATE_END:
AzureIoTClient 4:98007eb79fa8 1034 /* Codes_SRS_CONNECTION_01_237: [END - - TCP Close] */
AzureIoTClient 28:add19eb7defa 1035 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1036 {
AzureIoTClient 28:add19eb7defa 1037 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 1038 }
AzureIoTClient 28:add19eb7defa 1039 break;
AzureIoTClient 4:98007eb79fa8 1040 }
AzureIoTClient 4:98007eb79fa8 1041 }
AzureIoTClient 4:98007eb79fa8 1042 }
Azure.IoT Build 0:6ae2f7bca550 1043 }
Azure.IoT Build 0:6ae2f7bca550 1044
Azure.IoT Build 0:6ae2f7bca550 1045 static void frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 1046 {
AzureIoTClient 6:641a9672db08 1047 /* Bug: some error handling should happen here
AzureIoTClient 6:641a9672db08 1048 Filed: uAMQP: frame_codec error and amqp_frame_codec_error should handle the errors */
AzureIoTClient 28:add19eb7defa 1049 LogError("A frame_codec_error occured");
AzureIoTClient 28:add19eb7defa 1050 (void)context;
Azure.IoT Build 0:6ae2f7bca550 1051 }
Azure.IoT Build 0:6ae2f7bca550 1052
Azure.IoT Build 0:6ae2f7bca550 1053 static void amqp_frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 1054 {
AzureIoTClient 6:641a9672db08 1055 /* Bug: some error handling should happen here
AzureIoTClient 6:641a9672db08 1056 Filed: uAMQP: frame_codec error and amqp_frame_codec_error should handle the errors */
AzureIoTClient 28:add19eb7defa 1057 LogError("An amqp_frame_codec_error occured");
AzureIoTClient 28:add19eb7defa 1058 (void)context;
Azure.IoT Build 0:6ae2f7bca550 1059 }
Azure.IoT Build 0:6ae2f7bca550 1060
Azure.IoT Build 0:6ae2f7bca550 1061 /* Codes_SRS_CONNECTION_01_001: [connection_create shall open a new connection to a specified host/port.] */
Azure.IoT Build 0:6ae2f7bca550 1062 CONNECTION_HANDLE connection_create(XIO_HANDLE xio, const char* hostname, const char* container_id, ON_NEW_ENDPOINT on_new_endpoint, void* callback_context)
Azure.IoT Build 0:6ae2f7bca550 1063 {
Azure.IoT Build 5:ae49385aff34 1064 return connection_create2(xio, hostname, container_id, on_new_endpoint, callback_context, NULL, NULL, NULL, NULL);
Azure.IoT Build 0:6ae2f7bca550 1065 }
Azure.IoT Build 0:6ae2f7bca550 1066
Azure.IoT Build 0:6ae2f7bca550 1067 /* Codes_SRS_CONNECTION_01_001: [connection_create shall open a new connection to a specified host/port.] */
Azure.IoT Build 0:6ae2f7bca550 1068 /* Codes_SRS_CONNECTION_22_002: [connection_create shall allow registering connections state and io error callbacks.] */
Azure.IoT Build 5:ae49385aff34 1069 CONNECTION_HANDLE connection_create2(XIO_HANDLE xio, const char* hostname, const char* container_id, ON_NEW_ENDPOINT on_new_endpoint, void* callback_context, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* on_connection_state_changed_context, ON_IO_ERROR on_io_error, void* on_io_error_context)
Azure.IoT Build 0:6ae2f7bca550 1070 {
AzureIoTClient 35:d0bed2404ee9 1071 CONNECTION_HANDLE connection;
Azure.IoT Build 0:6ae2f7bca550 1072
AzureIoTClient 4:98007eb79fa8 1073 if ((xio == NULL) ||
AzureIoTClient 4:98007eb79fa8 1074 (container_id == NULL))
AzureIoTClient 4:98007eb79fa8 1075 {
AzureIoTClient 4:98007eb79fa8 1076 /* Codes_SRS_CONNECTION_01_071: [If xio or container_id is NULL, connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1077 LogError("Bad arguments: xio = %p, container_id = %p",
AzureIoTClient 28:add19eb7defa 1078 xio, container_id);
AzureIoTClient 35:d0bed2404ee9 1079 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1080 }
AzureIoTClient 4:98007eb79fa8 1081 else
AzureIoTClient 4:98007eb79fa8 1082 {
AzureIoTClient 35:d0bed2404ee9 1083 connection = (CONNECTION_HANDLE)malloc(sizeof(CONNECTION_INSTANCE));
AzureIoTClient 4:98007eb79fa8 1084 /* Codes_SRS_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 35:d0bed2404ee9 1085 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1086 {
AzureIoTClient 28:add19eb7defa 1087 LogError("Cannot allocate memory for connection");
AzureIoTClient 28:add19eb7defa 1088 }
AzureIoTClient 28:add19eb7defa 1089 else
AzureIoTClient 28:add19eb7defa 1090 {
AzureIoTClient 35:d0bed2404ee9 1091 connection->io = xio;
Azure.IoT Build 0:6ae2f7bca550 1092
AzureIoTClient 4:98007eb79fa8 1093 /* Codes_SRS_CONNECTION_01_082: [connection_create shall allocate a new frame_codec instance to be used for frame encoding/decoding.] */
AzureIoTClient 35:d0bed2404ee9 1094 connection->frame_codec = frame_codec_create(frame_codec_error, connection);
AzureIoTClient 35:d0bed2404ee9 1095 if (connection->frame_codec == NULL)
AzureIoTClient 4:98007eb79fa8 1096 {
AzureIoTClient 4:98007eb79fa8 1097 /* Codes_SRS_CONNECTION_01_083: [If frame_codec_create fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1098 LogError("Cannot create frame_codec");
AzureIoTClient 35:d0bed2404ee9 1099 free(connection);
AzureIoTClient 35:d0bed2404ee9 1100 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1101 }
AzureIoTClient 4:98007eb79fa8 1102 else
AzureIoTClient 4:98007eb79fa8 1103 {
AzureIoTClient 35:d0bed2404ee9 1104 connection->amqp_frame_codec = amqp_frame_codec_create(connection->frame_codec, on_amqp_frame_received, on_empty_amqp_frame_received, amqp_frame_codec_error, connection);
AzureIoTClient 35:d0bed2404ee9 1105 if (connection->amqp_frame_codec == NULL)
AzureIoTClient 4:98007eb79fa8 1106 {
AzureIoTClient 4:98007eb79fa8 1107 /* Codes_SRS_CONNECTION_01_108: [If amqp_frame_codec_create fails, connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1108 LogError("Cannot create amqp_frame_codec");
AzureIoTClient 35:d0bed2404ee9 1109 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1110 free(connection);
AzureIoTClient 35:d0bed2404ee9 1111 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1112 }
AzureIoTClient 4:98007eb79fa8 1113 else
AzureIoTClient 4:98007eb79fa8 1114 {
AzureIoTClient 4:98007eb79fa8 1115 if (hostname != NULL)
AzureIoTClient 4:98007eb79fa8 1116 {
AzureIoTClient 23:1111ee8bcba4 1117 size_t hostname_length = strlen(hostname);
AzureIoTClient 35:d0bed2404ee9 1118 connection->host_name = (char*)malloc(hostname_length + 1);
AzureIoTClient 35:d0bed2404ee9 1119 if (connection->host_name == NULL)
AzureIoTClient 4:98007eb79fa8 1120 {
AzureIoTClient 4:98007eb79fa8 1121 /* Codes_SRS_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1122 LogError("Cannot allocate memory for host name");
AzureIoTClient 35:d0bed2404ee9 1123 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1124 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1125 free(connection);
AzureIoTClient 35:d0bed2404ee9 1126 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1127 }
AzureIoTClient 4:98007eb79fa8 1128 else
AzureIoTClient 4:98007eb79fa8 1129 {
AzureIoTClient 35:d0bed2404ee9 1130 (void)memcpy(connection->host_name, hostname, hostname_length + 1);
AzureIoTClient 4:98007eb79fa8 1131 }
AzureIoTClient 4:98007eb79fa8 1132 }
AzureIoTClient 4:98007eb79fa8 1133 else
AzureIoTClient 4:98007eb79fa8 1134 {
AzureIoTClient 35:d0bed2404ee9 1135 connection->host_name = NULL;
AzureIoTClient 4:98007eb79fa8 1136 }
Azure.IoT Build 0:6ae2f7bca550 1137
AzureIoTClient 35:d0bed2404ee9 1138 if (connection != NULL)
AzureIoTClient 4:98007eb79fa8 1139 {
AzureIoTClient 23:1111ee8bcba4 1140 size_t container_id_length = strlen(container_id);
AzureIoTClient 35:d0bed2404ee9 1141 connection->container_id = (char*)malloc(container_id_length + 1);
AzureIoTClient 35:d0bed2404ee9 1142 if (connection->container_id == NULL)
AzureIoTClient 4:98007eb79fa8 1143 {
AzureIoTClient 4:98007eb79fa8 1144 /* Codes_SRS_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1145 LogError("Cannot allocate memory for container_id");
AzureIoTClient 35:d0bed2404ee9 1146 free(connection->host_name);
AzureIoTClient 35:d0bed2404ee9 1147 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1148 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1149 free(connection);
AzureIoTClient 35:d0bed2404ee9 1150 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1151 }
AzureIoTClient 4:98007eb79fa8 1152 else
AzureIoTClient 4:98007eb79fa8 1153 {
AzureIoTClient 35:d0bed2404ee9 1154 connection->tick_counter = tickcounter_create();
AzureIoTClient 35:d0bed2404ee9 1155 if (connection->tick_counter == NULL)
AzureIoTClient 4:98007eb79fa8 1156 {
AzureIoTClient 28:add19eb7defa 1157 LogError("Cannot create tick counter");
AzureIoTClient 35:d0bed2404ee9 1158 free(connection->container_id);
AzureIoTClient 35:d0bed2404ee9 1159 free(connection->host_name);
AzureIoTClient 35:d0bed2404ee9 1160 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1161 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1162 free(connection);
AzureIoTClient 35:d0bed2404ee9 1163 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1164 }
AzureIoTClient 4:98007eb79fa8 1165 else
AzureIoTClient 4:98007eb79fa8 1166 {
AzureIoTClient 35:d0bed2404ee9 1167 (void)memcpy(connection->container_id, container_id, container_id_length + 1);
Azure.IoT Build 0:6ae2f7bca550 1168
AzureIoTClient 4:98007eb79fa8 1169 /* Codes_SRS_CONNECTION_01_173: [<field name="max-frame-size" type="uint" default="4294967295"/>] */
AzureIoTClient 35:d0bed2404ee9 1170 connection->max_frame_size = 4294967295u;
AzureIoTClient 4:98007eb79fa8 1171 /* Codes: [<field name="channel-max" type="ushort" default="65535"/>] */
AzureIoTClient 35:d0bed2404ee9 1172 connection->channel_max = 65535;
Azure.IoT Build 0:6ae2f7bca550 1173
AzureIoTClient 4:98007eb79fa8 1174 /* Codes_SRS_CONNECTION_01_175: [<field name="idle-time-out" type="milliseconds"/>] */
AzureIoTClient 4:98007eb79fa8 1175 /* Codes_SRS_CONNECTION_01_192: [A value of zero is the same as if it was not set (null).] */
AzureIoTClient 35:d0bed2404ee9 1176 connection->idle_timeout = 0;
AzureIoTClient 35:d0bed2404ee9 1177 connection->remote_idle_timeout = 0;
AzureIoTClient 35:d0bed2404ee9 1178 connection->remote_idle_timeout_send_frame_millisecond = 0;
AzureIoTClient 35:d0bed2404ee9 1179 connection->idle_timeout_empty_frame_send_ratio = 0.5;
Azure.IoT Build 0:6ae2f7bca550 1180
AzureIoTClient 35:d0bed2404ee9 1181 connection->endpoint_count = 0;
AzureIoTClient 35:d0bed2404ee9 1182 connection->endpoints = NULL;
AzureIoTClient 35:d0bed2404ee9 1183 connection->header_bytes_received = 0;
AzureIoTClient 35:d0bed2404ee9 1184 connection->is_remote_frame_received = 0;
Azure.IoT Build 0:6ae2f7bca550 1185
AzureIoTClient 35:d0bed2404ee9 1186 connection->is_underlying_io_open = 0;
AzureIoTClient 35:d0bed2404ee9 1187 connection->remote_max_frame_size = 512;
AzureIoTClient 35:d0bed2404ee9 1188 connection->is_trace_on = 0;
Azure.IoT Build 0:6ae2f7bca550 1189
AzureIoTClient 4:98007eb79fa8 1190 /* Mark that settings have not yet been set by the user */
AzureIoTClient 35:d0bed2404ee9 1191 connection->idle_timeout_specified = 0;
Azure.IoT Build 0:6ae2f7bca550 1192
AzureIoTClient 35:d0bed2404ee9 1193 connection->on_new_endpoint = on_new_endpoint;
AzureIoTClient 35:d0bed2404ee9 1194 connection->on_new_endpoint_callback_context = callback_context;
Azure.IoT Build 0:6ae2f7bca550 1195
AzureIoTClient 35:d0bed2404ee9 1196 connection->on_io_error = on_io_error;
AzureIoTClient 35:d0bed2404ee9 1197 connection->on_io_error_callback_context = on_io_error_context;
AzureIoTClient 35:d0bed2404ee9 1198 connection->on_connection_state_changed = on_connection_state_changed;
AzureIoTClient 35:d0bed2404ee9 1199 connection->on_connection_state_changed_callback_context = on_connection_state_changed_context;
Azure.IoT Build 0:6ae2f7bca550 1200
AzureIoTClient 35:d0bed2404ee9 1201 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 20:206846c14c80 1202 {
AzureIoTClient 20:206846c14c80 1203 LogError("Could not retrieve time for last frame received time");
AzureIoTClient 35:d0bed2404ee9 1204 tickcounter_destroy(connection->tick_counter);
AzureIoTClient 35:d0bed2404ee9 1205 free(connection->container_id);
AzureIoTClient 35:d0bed2404ee9 1206 free(connection->host_name);
AzureIoTClient 35:d0bed2404ee9 1207 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1208 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1209 free(connection);
AzureIoTClient 35:d0bed2404ee9 1210 connection = NULL;
AzureIoTClient 20:206846c14c80 1211 }
AzureIoTClient 20:206846c14c80 1212 else
AzureIoTClient 20:206846c14c80 1213 {
AzureIoTClient 35:d0bed2404ee9 1214 connection->last_frame_sent_time = connection->last_frame_received_time;
AzureIoTClient 20:206846c14c80 1215
AzureIoTClient 20:206846c14c80 1216 /* Codes_SRS_CONNECTION_01_072: [When connection_create succeeds, the state of the connection shall be CONNECTION_STATE_START.] */
AzureIoTClient 35:d0bed2404ee9 1217 connection_set_state(connection, CONNECTION_STATE_START);
AzureIoTClient 20:206846c14c80 1218 }
AzureIoTClient 4:98007eb79fa8 1219 }
AzureIoTClient 4:98007eb79fa8 1220 }
AzureIoTClient 4:98007eb79fa8 1221 }
AzureIoTClient 4:98007eb79fa8 1222 }
AzureIoTClient 4:98007eb79fa8 1223 }
AzureIoTClient 4:98007eb79fa8 1224 }
AzureIoTClient 4:98007eb79fa8 1225 }
Azure.IoT Build 0:6ae2f7bca550 1226
AzureIoTClient 35:d0bed2404ee9 1227 return connection;
Azure.IoT Build 0:6ae2f7bca550 1228 }
Azure.IoT Build 0:6ae2f7bca550 1229
Azure.IoT Build 0:6ae2f7bca550 1230 void connection_destroy(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1231 {
AzureIoTClient 4:98007eb79fa8 1232 /* Codes_SRS_CONNECTION_01_079: [If handle is NULL, connection_destroy shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1233 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1234 {
AzureIoTClient 28:add19eb7defa 1235 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1236 }
AzureIoTClient 28:add19eb7defa 1237 else
AzureIoTClient 28:add19eb7defa 1238 {
AzureIoTClient 4:98007eb79fa8 1239 /* Codes_SRS_CONNECTION_01_073: [connection_destroy shall free all resources associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1240 if (connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1241 {
AzureIoTClient 24:2c59c2d43ebf 1242 (void)connection_close(connection, NULL, NULL);
AzureIoTClient 4:98007eb79fa8 1243 }
Azure.IoT Build 0:6ae2f7bca550 1244
AzureIoTClient 4:98007eb79fa8 1245 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 4:98007eb79fa8 1246 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 4:98007eb79fa8 1247 tickcounter_destroy(connection->tick_counter);
Azure.IoT Build 0:6ae2f7bca550 1248
AzureIoTClient 21:f9c433d8e6ca 1249 free(connection->host_name);
AzureIoTClient 21:f9c433d8e6ca 1250 free(connection->container_id);
Azure.IoT Build 0:6ae2f7bca550 1251
AzureIoTClient 4:98007eb79fa8 1252 /* Codes_SRS_CONNECTION_01_074: [connection_destroy shall close the socket connection.] */
AzureIoTClient 21:f9c433d8e6ca 1253 free(connection);
AzureIoTClient 4:98007eb79fa8 1254 }
Azure.IoT Build 0:6ae2f7bca550 1255 }
Azure.IoT Build 0:6ae2f7bca550 1256
Azure.IoT Build 0:6ae2f7bca550 1257 int connection_open(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1258 {
AzureIoTClient 4:98007eb79fa8 1259 int result;
Azure.IoT Build 0:6ae2f7bca550 1260
AzureIoTClient 4:98007eb79fa8 1261 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1262 {
AzureIoTClient 28:add19eb7defa 1263 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1264 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1265 }
AzureIoTClient 4:98007eb79fa8 1266 else
AzureIoTClient 4:98007eb79fa8 1267 {
AzureIoTClient 4:98007eb79fa8 1268 if (!connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1269 {
AzureIoTClient 4:98007eb79fa8 1270 if (xio_open(connection->io, connection_on_io_open_complete, connection, connection_on_bytes_received, connection, connection_on_io_error, connection) != 0)
AzureIoTClient 4:98007eb79fa8 1271 {
AzureIoTClient 28:add19eb7defa 1272 LogError("Opening the underlying IO failed");
AzureIoTClient 28:add19eb7defa 1273 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 1274 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1275 }
AzureIoTClient 4:98007eb79fa8 1276 else
AzureIoTClient 4:98007eb79fa8 1277 {
AzureIoTClient 4:98007eb79fa8 1278 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1279
AzureIoTClient 4:98007eb79fa8 1280 connection_set_state(connection, CONNECTION_STATE_START);
Azure.IoT Build 0:6ae2f7bca550 1281
AzureIoTClient 4:98007eb79fa8 1282 result = 0;
AzureIoTClient 4:98007eb79fa8 1283 }
AzureIoTClient 4:98007eb79fa8 1284 }
AzureIoTClient 4:98007eb79fa8 1285 else
AzureIoTClient 4:98007eb79fa8 1286 {
AzureIoTClient 4:98007eb79fa8 1287 result = 0;
AzureIoTClient 4:98007eb79fa8 1288 }
AzureIoTClient 4:98007eb79fa8 1289 }
Azure.IoT Build 0:6ae2f7bca550 1290
AzureIoTClient 4:98007eb79fa8 1291 return result;
Azure.IoT Build 0:6ae2f7bca550 1292 }
Azure.IoT Build 0:6ae2f7bca550 1293
Azure.IoT Build 0:6ae2f7bca550 1294 int connection_listen(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1295 {
AzureIoTClient 4:98007eb79fa8 1296 int result;
Azure.IoT Build 0:6ae2f7bca550 1297
AzureIoTClient 4:98007eb79fa8 1298 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1299 {
AzureIoTClient 28:add19eb7defa 1300 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1301 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1302 }
AzureIoTClient 4:98007eb79fa8 1303 else
AzureIoTClient 4:98007eb79fa8 1304 {
AzureIoTClient 4:98007eb79fa8 1305 if (!connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1306 {
AzureIoTClient 4:98007eb79fa8 1307 if (xio_open(connection->io, connection_on_io_open_complete, connection, connection_on_bytes_received, connection, connection_on_io_error, connection) != 0)
AzureIoTClient 4:98007eb79fa8 1308 {
AzureIoTClient 28:add19eb7defa 1309 LogError("Opening the underlying IO failed");
AzureIoTClient 28:add19eb7defa 1310 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 1311 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1312 }
AzureIoTClient 4:98007eb79fa8 1313 else
AzureIoTClient 4:98007eb79fa8 1314 {
AzureIoTClient 4:98007eb79fa8 1315 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1316
AzureIoTClient 4:98007eb79fa8 1317 connection_set_state(connection, CONNECTION_STATE_HDR_EXCH);
Azure.IoT Build 0:6ae2f7bca550 1318
AzureIoTClient 4:98007eb79fa8 1319 result = 0;
AzureIoTClient 4:98007eb79fa8 1320 }
AzureIoTClient 4:98007eb79fa8 1321 }
AzureIoTClient 4:98007eb79fa8 1322 else
AzureIoTClient 4:98007eb79fa8 1323 {
AzureIoTClient 4:98007eb79fa8 1324 result = 0;
AzureIoTClient 4:98007eb79fa8 1325 }
AzureIoTClient 4:98007eb79fa8 1326 }
Azure.IoT Build 0:6ae2f7bca550 1327
AzureIoTClient 4:98007eb79fa8 1328 return result;
Azure.IoT Build 0:6ae2f7bca550 1329 }
Azure.IoT Build 0:6ae2f7bca550 1330
Azure.IoT Build 0:6ae2f7bca550 1331 int connection_close(CONNECTION_HANDLE connection, const char* condition_value, const char* description)
Azure.IoT Build 0:6ae2f7bca550 1332 {
AzureIoTClient 4:98007eb79fa8 1333 int result;
Azure.IoT Build 0:6ae2f7bca550 1334
AzureIoTClient 4:98007eb79fa8 1335 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1336 {
AzureIoTClient 28:add19eb7defa 1337 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1338 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1339 }
AzureIoTClient 4:98007eb79fa8 1340 else
AzureIoTClient 4:98007eb79fa8 1341 {
AzureIoTClient 4:98007eb79fa8 1342 if (condition_value != NULL)
AzureIoTClient 4:98007eb79fa8 1343 {
AzureIoTClient 4:98007eb79fa8 1344 close_connection_with_error(connection, condition_value, description);
AzureIoTClient 4:98007eb79fa8 1345 }
AzureIoTClient 4:98007eb79fa8 1346 else
AzureIoTClient 4:98007eb79fa8 1347 {
AzureIoTClient 28:add19eb7defa 1348 if (send_close_frame(connection, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1349 {
AzureIoTClient 28:add19eb7defa 1350 LogError("Sending CLOSE frame failed");
AzureIoTClient 28:add19eb7defa 1351 }
AzureIoTClient 24:2c59c2d43ebf 1352
AzureIoTClient 4:98007eb79fa8 1353 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 1354 }
Azure.IoT Build 0:6ae2f7bca550 1355
AzureIoTClient 28:add19eb7defa 1356 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1357 {
AzureIoTClient 28:add19eb7defa 1358 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 1359 }
AzureIoTClient 24:2c59c2d43ebf 1360
AzureIoTClient 28:add19eb7defa 1361 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1362
Azure.IoT Build 0:6ae2f7bca550 1363 result = 0;
AzureIoTClient 4:98007eb79fa8 1364 }
Azure.IoT Build 0:6ae2f7bca550 1365
AzureIoTClient 4:98007eb79fa8 1366 return result;
Azure.IoT Build 0:6ae2f7bca550 1367 }
Azure.IoT Build 0:6ae2f7bca550 1368
Azure.IoT Build 0:6ae2f7bca550 1369 int connection_set_max_frame_size(CONNECTION_HANDLE connection, uint32_t max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1370 {
AzureIoTClient 4:98007eb79fa8 1371 int result;
Azure.IoT Build 0:6ae2f7bca550 1372
AzureIoTClient 4:98007eb79fa8 1373 /* Codes_SRS_CONNECTION_01_163: [If connection is NULL, connection_set_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1374 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1375 {
AzureIoTClient 28:add19eb7defa 1376 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1377 result = __FAILURE__;
AzureIoTClient 28:add19eb7defa 1378 }
AzureIoTClient 28:add19eb7defa 1379 /* Codes_SRS_CONNECTION_01_150: [If the max_frame_size is invalid then connection_set_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1380 /* Codes_SRS_CONNECTION_01_167: [Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.] */
AzureIoTClient 28:add19eb7defa 1381 else if (max_frame_size < 512)
AzureIoTClient 28:add19eb7defa 1382 {
AzureIoTClient 28:add19eb7defa 1383 LogError("max_frame_size too small");
AzureIoTClient 28:add19eb7defa 1384 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1385 }
AzureIoTClient 4:98007eb79fa8 1386 else
AzureIoTClient 4:98007eb79fa8 1387 {
AzureIoTClient 4:98007eb79fa8 1388 /* Codes_SRS_CONNECTION_01_157: [If connection_set_max_frame_size is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1389 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1390 {
AzureIoTClient 28:add19eb7defa 1391 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1392 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1393 }
AzureIoTClient 4:98007eb79fa8 1394 else
AzureIoTClient 4:98007eb79fa8 1395 {
AzureIoTClient 4:98007eb79fa8 1396 /* Codes_SRS_CONNECTION_01_148: [connection_set_max_frame_size shall set the max_frame_size associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1397 /* Codes_SRS_CONNECTION_01_164: [If connection_set_max_frame_size fails, the previous max_frame_size setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1398 connection->max_frame_size = max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1399
AzureIoTClient 4:98007eb79fa8 1400 /* Codes_SRS_CONNECTION_01_149: [On success connection_set_max_frame_size shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1401 result = 0;
AzureIoTClient 4:98007eb79fa8 1402 }
AzureIoTClient 4:98007eb79fa8 1403 }
Azure.IoT Build 0:6ae2f7bca550 1404
AzureIoTClient 4:98007eb79fa8 1405 return result;
Azure.IoT Build 0:6ae2f7bca550 1406 }
Azure.IoT Build 0:6ae2f7bca550 1407
Azure.IoT Build 0:6ae2f7bca550 1408 int connection_get_max_frame_size(CONNECTION_HANDLE connection, uint32_t* max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1409 {
AzureIoTClient 4:98007eb79fa8 1410 int result;
Azure.IoT Build 0:6ae2f7bca550 1411
AzureIoTClient 4:98007eb79fa8 1412 /* Codes_SRS_CONNECTION_01_170: [If connection or max_frame_size is NULL, connection_get_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1413 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1414 (max_frame_size == NULL))
AzureIoTClient 4:98007eb79fa8 1415 {
AzureIoTClient 28:add19eb7defa 1416 LogError("Bad arguments: connection = %p, max_frame_size = %p",
AzureIoTClient 28:add19eb7defa 1417 connection, max_frame_size);
AzureIoTClient 28:add19eb7defa 1418 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1419 }
AzureIoTClient 4:98007eb79fa8 1420 else
AzureIoTClient 4:98007eb79fa8 1421 {
AzureIoTClient 4:98007eb79fa8 1422 /* Codes_SRS_CONNECTION_01_168: [connection_get_max_frame_size shall return in the max_frame_size argument the current max frame size setting.] */
AzureIoTClient 4:98007eb79fa8 1423 *max_frame_size = connection->max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1424
AzureIoTClient 4:98007eb79fa8 1425 /* Codes_SRS_CONNECTION_01_169: [On success, connection_get_max_frame_size shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1426 result = 0;
AzureIoTClient 4:98007eb79fa8 1427 }
Azure.IoT Build 0:6ae2f7bca550 1428
AzureIoTClient 4:98007eb79fa8 1429 return result;
Azure.IoT Build 0:6ae2f7bca550 1430 }
Azure.IoT Build 0:6ae2f7bca550 1431
Azure.IoT Build 0:6ae2f7bca550 1432 int connection_set_channel_max(CONNECTION_HANDLE connection, uint16_t channel_max)
Azure.IoT Build 0:6ae2f7bca550 1433 {
AzureIoTClient 4:98007eb79fa8 1434 int result;
Azure.IoT Build 0:6ae2f7bca550 1435
AzureIoTClient 4:98007eb79fa8 1436 /* Codes_SRS_CONNECTION_01_181: [If connection is NULL then connection_set_channel_max shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1437 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1438 {
AzureIoTClient 28:add19eb7defa 1439 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1440 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1441 }
AzureIoTClient 4:98007eb79fa8 1442 else
AzureIoTClient 4:98007eb79fa8 1443 {
AzureIoTClient 4:98007eb79fa8 1444 /* Codes_SRS_CONNECTION_01_156: [If connection_set_channel_max is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1445 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1446 {
AzureIoTClient 28:add19eb7defa 1447 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1448 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1449 }
AzureIoTClient 4:98007eb79fa8 1450 else
AzureIoTClient 4:98007eb79fa8 1451 {
AzureIoTClient 4:98007eb79fa8 1452 /* Codes_SRS_CONNECTION_01_153: [connection_set_channel_max shall set the channel_max associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1453 /* Codes_SRS_CONNECTION_01_165: [If connection_set_channel_max fails, the previous channel_max setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1454 connection->channel_max = channel_max;
Azure.IoT Build 0:6ae2f7bca550 1455
AzureIoTClient 4:98007eb79fa8 1456 /* Codes_SRS_CONNECTION_01_154: [On success connection_set_channel_max shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1457 result = 0;
AzureIoTClient 4:98007eb79fa8 1458 }
AzureIoTClient 4:98007eb79fa8 1459 }
Azure.IoT Build 0:6ae2f7bca550 1460
AzureIoTClient 4:98007eb79fa8 1461 return result;
Azure.IoT Build 0:6ae2f7bca550 1462 }
Azure.IoT Build 0:6ae2f7bca550 1463
Azure.IoT Build 0:6ae2f7bca550 1464 int connection_get_channel_max(CONNECTION_HANDLE connection, uint16_t* channel_max)
Azure.IoT Build 0:6ae2f7bca550 1465 {
AzureIoTClient 4:98007eb79fa8 1466 int result;
Azure.IoT Build 0:6ae2f7bca550 1467
AzureIoTClient 4:98007eb79fa8 1468 /* Codes_SRS_CONNECTION_01_184: [If connection or channel_max is NULL, connection_get_channel_max shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1469 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1470 (channel_max == NULL))
AzureIoTClient 4:98007eb79fa8 1471 {
AzureIoTClient 28:add19eb7defa 1472 LogError("Bad arguments: connection = %p, channel_max = %p",
AzureIoTClient 28:add19eb7defa 1473 connection, channel_max);
AzureIoTClient 28:add19eb7defa 1474 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1475 }
AzureIoTClient 4:98007eb79fa8 1476 else
AzureIoTClient 4:98007eb79fa8 1477 {
AzureIoTClient 4:98007eb79fa8 1478 /* Codes_SRS_CONNECTION_01_182: [connection_get_channel_max shall return in the channel_max argument the current channel_max setting.] */
AzureIoTClient 4:98007eb79fa8 1479 *channel_max = connection->channel_max;
Azure.IoT Build 0:6ae2f7bca550 1480
AzureIoTClient 4:98007eb79fa8 1481 /* Codes_SRS_CONNECTION_01_183: [On success, connection_get_channel_max shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1482 result = 0;
AzureIoTClient 4:98007eb79fa8 1483 }
Azure.IoT Build 0:6ae2f7bca550 1484
AzureIoTClient 4:98007eb79fa8 1485 return result;
Azure.IoT Build 0:6ae2f7bca550 1486 }
Azure.IoT Build 0:6ae2f7bca550 1487
Azure.IoT Build 0:6ae2f7bca550 1488 int connection_set_idle_timeout(CONNECTION_HANDLE connection, milliseconds idle_timeout)
Azure.IoT Build 0:6ae2f7bca550 1489 {
AzureIoTClient 4:98007eb79fa8 1490 int result;
Azure.IoT Build 0:6ae2f7bca550 1491
AzureIoTClient 4:98007eb79fa8 1492 /* Codes_SRS_CONNECTION_01_191: [If connection is NULL, connection_set_idle_timeout shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1493 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1494 {
AzureIoTClient 28:add19eb7defa 1495 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1496 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1497 }
AzureIoTClient 4:98007eb79fa8 1498 else
AzureIoTClient 4:98007eb79fa8 1499 {
AzureIoTClient 4:98007eb79fa8 1500 /* Codes_SRS_CONNECTION_01_158: [If connection_set_idle_timeout is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1501 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1502 {
AzureIoTClient 28:add19eb7defa 1503 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1504 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1505 }
AzureIoTClient 4:98007eb79fa8 1506 else
AzureIoTClient 4:98007eb79fa8 1507 {
AzureIoTClient 4:98007eb79fa8 1508 /* Codes_SRS_CONNECTION_01_159: [connection_set_idle_timeout shall set the idle_timeout associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1509 /* Codes_SRS_CONNECTION_01_166: [If connection_set_idle_timeout fails, the previous idle_timeout setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1510 connection->idle_timeout = idle_timeout;
AzureIoTClient 4:98007eb79fa8 1511 connection->idle_timeout_specified = true;
Azure.IoT Build 0:6ae2f7bca550 1512
AzureIoTClient 4:98007eb79fa8 1513 /* Codes_SRS_CONNECTION_01_160: [On success connection_set_idle_timeout shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1514 result = 0;
AzureIoTClient 4:98007eb79fa8 1515 }
AzureIoTClient 4:98007eb79fa8 1516 }
Azure.IoT Build 0:6ae2f7bca550 1517
AzureIoTClient 4:98007eb79fa8 1518 return result;
Azure.IoT Build 0:6ae2f7bca550 1519 }
Azure.IoT Build 0:6ae2f7bca550 1520
Azure.IoT Build 0:6ae2f7bca550 1521 int connection_get_idle_timeout(CONNECTION_HANDLE connection, milliseconds* idle_timeout)
Azure.IoT Build 0:6ae2f7bca550 1522 {
AzureIoTClient 4:98007eb79fa8 1523 int result;
Azure.IoT Build 0:6ae2f7bca550 1524
AzureIoTClient 4:98007eb79fa8 1525 /* Codes_SRS_CONNECTION_01_190: [If connection or idle_timeout is NULL, connection_get_idle_timeout shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1526 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1527 (idle_timeout == NULL))
AzureIoTClient 4:98007eb79fa8 1528 {
AzureIoTClient 28:add19eb7defa 1529 LogError("Bad arguments: connection = %p, idle_timeout = %p",
AzureIoTClient 28:add19eb7defa 1530 connection, idle_timeout);
AzureIoTClient 28:add19eb7defa 1531 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1532 }
AzureIoTClient 4:98007eb79fa8 1533 else
AzureIoTClient 4:98007eb79fa8 1534 {
AzureIoTClient 4:98007eb79fa8 1535 /* Codes_SRS_CONNECTION_01_188: [connection_get_idle_timeout shall return in the idle_timeout argument the current idle_timeout setting.] */
AzureIoTClient 4:98007eb79fa8 1536 *idle_timeout = connection->idle_timeout;
Azure.IoT Build 0:6ae2f7bca550 1537
AzureIoTClient 4:98007eb79fa8 1538 /* Codes_SRS_CONNECTION_01_189: [On success, connection_get_idle_timeout shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1539 result = 0;
AzureIoTClient 4:98007eb79fa8 1540 }
Azure.IoT Build 0:6ae2f7bca550 1541
AzureIoTClient 4:98007eb79fa8 1542 return result;
Azure.IoT Build 0:6ae2f7bca550 1543 }
Azure.IoT Build 0:6ae2f7bca550 1544
Azure.IoT Build 0:6ae2f7bca550 1545 int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1546 {
AzureIoTClient 4:98007eb79fa8 1547 int result;
Azure.IoT Build 0:6ae2f7bca550 1548
AzureIoTClient 4:98007eb79fa8 1549 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1550 (remote_max_frame_size == NULL))
AzureIoTClient 4:98007eb79fa8 1551 {
AzureIoTClient 28:add19eb7defa 1552 LogError("Bad arguments: connection = %p, remote_max_frame_size = %p",
AzureIoTClient 28:add19eb7defa 1553 connection, remote_max_frame_size);
AzureIoTClient 28:add19eb7defa 1554 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1555 }
AzureIoTClient 4:98007eb79fa8 1556 else
AzureIoTClient 4:98007eb79fa8 1557 {
AzureIoTClient 4:98007eb79fa8 1558 *remote_max_frame_size = connection->remote_max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1559
AzureIoTClient 4:98007eb79fa8 1560 result = 0;
AzureIoTClient 4:98007eb79fa8 1561 }
Azure.IoT Build 0:6ae2f7bca550 1562
AzureIoTClient 4:98007eb79fa8 1563 return result;
Azure.IoT Build 0:6ae2f7bca550 1564 }
Azure.IoT Build 0:6ae2f7bca550 1565
AzureIoTClient 1:eab586236bfe 1566 uint64_t connection_handle_deadlines(CONNECTION_HANDLE connection)
AzureIoTClient 1:eab586236bfe 1567 {
AzureIoTClient 35:d0bed2404ee9 1568 uint64_t local_deadline = (uint64_t)-1;
AzureIoTClient 1:eab586236bfe 1569 uint64_t remote_deadline = (uint64_t)-1;
AzureIoTClient 1:eab586236bfe 1570
AzureIoTClient 28:add19eb7defa 1571 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1572 {
AzureIoTClient 28:add19eb7defa 1573 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1574 }
AzureIoTClient 28:add19eb7defa 1575 else
AzureIoTClient 28:add19eb7defa 1576 {
Azure.IoT.Build 14:0b0e28c75ded 1577 tickcounter_ms_t current_ms;
AzureIoTClient 1:eab586236bfe 1578
AzureIoTClient 1:eab586236bfe 1579 if (tickcounter_get_current_ms(connection->tick_counter, &current_ms) != 0)
AzureIoTClient 1:eab586236bfe 1580 {
AzureIoTClient 28:add19eb7defa 1581 LogError("Could not get tick counter value");
AzureIoTClient 28:add19eb7defa 1582 close_connection_with_error(connection, "amqp:internal-error", "Could not get tick count");
AzureIoTClient 1:eab586236bfe 1583 }
AzureIoTClient 1:eab586236bfe 1584 else
AzureIoTClient 1:eab586236bfe 1585 {
AzureIoTClient 1:eab586236bfe 1586 if (connection->idle_timeout_specified && (connection->idle_timeout != 0))
AzureIoTClient 1:eab586236bfe 1587 {
AzureIoTClient 1:eab586236bfe 1588 /* Calculate time until configured idle timeout expires */
AzureIoTClient 1:eab586236bfe 1589
AzureIoTClient 1:eab586236bfe 1590 uint64_t time_since_last_received = current_ms - connection->last_frame_received_time;
AzureIoTClient 1:eab586236bfe 1591 if (time_since_last_received < connection->idle_timeout)
AzureIoTClient 1:eab586236bfe 1592 {
AzureIoTClient 1:eab586236bfe 1593 local_deadline = connection->idle_timeout - time_since_last_received;
AzureIoTClient 1:eab586236bfe 1594 }
AzureIoTClient 1:eab586236bfe 1595 else
AzureIoTClient 1:eab586236bfe 1596 {
AzureIoTClient 1:eab586236bfe 1597 local_deadline = 0;
AzureIoTClient 1:eab586236bfe 1598
AzureIoTClient 1:eab586236bfe 1599 /* close connection */
AzureIoTClient 1:eab586236bfe 1600 close_connection_with_error(connection, "amqp:internal-error", "No frame received for the idle timeout");
AzureIoTClient 1:eab586236bfe 1601 }
AzureIoTClient 1:eab586236bfe 1602 }
AzureIoTClient 1:eab586236bfe 1603
AzureIoTClient 1:eab586236bfe 1604 if (local_deadline != 0 && connection->remote_idle_timeout != 0)
AzureIoTClient 1:eab586236bfe 1605 {
AzureIoTClient 1:eab586236bfe 1606 /* Calculate time until remote idle timeout expires */
AzureIoTClient 1:eab586236bfe 1607
AzureIoTClient 35:d0bed2404ee9 1608 uint64_t remote_idle_timeout = connection->remote_idle_timeout_send_frame_millisecond;
AzureIoTClient 1:eab586236bfe 1609 uint64_t time_since_last_sent = current_ms - connection->last_frame_sent_time;
AzureIoTClient 1:eab586236bfe 1610
AzureIoTClient 1:eab586236bfe 1611 if (time_since_last_sent < remote_idle_timeout)
AzureIoTClient 1:eab586236bfe 1612 {
AzureIoTClient 1:eab586236bfe 1613 remote_deadline = remote_idle_timeout - time_since_last_sent;
AzureIoTClient 1:eab586236bfe 1614 }
AzureIoTClient 1:eab586236bfe 1615 else
AzureIoTClient 1:eab586236bfe 1616 {
AzureIoTClient 1:eab586236bfe 1617 connection->on_send_complete = NULL;
AzureIoTClient 1:eab586236bfe 1618 if (amqp_frame_codec_encode_empty_frame(connection->amqp_frame_codec, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 1:eab586236bfe 1619 {
AzureIoTClient 28:add19eb7defa 1620 LogError("Encoding the empty frame failed");
AzureIoTClient 28:add19eb7defa 1621 /* close connection */
AzureIoTClient 28:add19eb7defa 1622 close_connection_with_error(connection, "amqp:internal-error", "Cannot send empty frame");
AzureIoTClient 1:eab586236bfe 1623 }
AzureIoTClient 1:eab586236bfe 1624 else
AzureIoTClient 1:eab586236bfe 1625 {
AzureIoTClient 6:641a9672db08 1626 if (connection->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 1627 {
AzureIoTClient 16:22a72cf8e416 1628 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Empty frame");
AzureIoTClient 6:641a9672db08 1629 }
AzureIoTClient 1:eab586236bfe 1630
AzureIoTClient 1:eab586236bfe 1631 connection->last_frame_sent_time = current_ms;
AzureIoTClient 1:eab586236bfe 1632
AzureIoTClient 1:eab586236bfe 1633 remote_deadline = remote_idle_timeout;
AzureIoTClient 1:eab586236bfe 1634 }
AzureIoTClient 1:eab586236bfe 1635 }
AzureIoTClient 1:eab586236bfe 1636 }
AzureIoTClient 1:eab586236bfe 1637 }
AzureIoTClient 1:eab586236bfe 1638 }
AzureIoTClient 1:eab586236bfe 1639
AzureIoTClient 1:eab586236bfe 1640 /* Return the shorter of each deadline, or 0 to indicate connection closed */
AzureIoTClient 1:eab586236bfe 1641 return local_deadline > remote_deadline ? remote_deadline : local_deadline;
AzureIoTClient 1:eab586236bfe 1642 }
AzureIoTClient 1:eab586236bfe 1643
Azure.IoT Build 0:6ae2f7bca550 1644 void connection_dowork(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1645 {
AzureIoTClient 4:98007eb79fa8 1646 /* Codes_SRS_CONNECTION_01_078: [If handle is NULL, connection_dowork shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1647 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1648 {
AzureIoTClient 28:add19eb7defa 1649 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1650 }
AzureIoTClient 28:add19eb7defa 1651 else
AzureIoTClient 28:add19eb7defa 1652 {
AzureIoTClient 1:eab586236bfe 1653 if (connection_handle_deadlines(connection) > 0)
AzureIoTClient 1:eab586236bfe 1654 {
AzureIoTClient 1:eab586236bfe 1655 /* Codes_SRS_CONNECTION_01_076: [connection_dowork shall schedule the underlying IO interface to do its work by calling xio_dowork.] */
AzureIoTClient 1:eab586236bfe 1656 xio_dowork(connection->io);
AzureIoTClient 1:eab586236bfe 1657 }
AzureIoTClient 1:eab586236bfe 1658 }
Azure.IoT Build 0:6ae2f7bca550 1659 }
Azure.IoT Build 0:6ae2f7bca550 1660
Azure.IoT Build 0:6ae2f7bca550 1661 ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1662 {
AzureIoTClient 28:add19eb7defa 1663 ENDPOINT_HANDLE result;
Azure.IoT Build 0:6ae2f7bca550 1664
AzureIoTClient 4:98007eb79fa8 1665 /* Codes_SRS_CONNECTION_01_113: [If connection, on_endpoint_frame_received or on_connection_state_changed is NULL, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 4:98007eb79fa8 1666 /* Codes_SRS_CONNECTION_01_193: [The context argument shall be allowed to be NULL.] */
AzureIoTClient 4:98007eb79fa8 1667 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1668 {
AzureIoTClient 28:add19eb7defa 1669 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1670 result = NULL;
AzureIoTClient 4:98007eb79fa8 1671 }
AzureIoTClient 4:98007eb79fa8 1672 else
AzureIoTClient 4:98007eb79fa8 1673 {
AzureIoTClient 4:98007eb79fa8 1674 /* Codes_SRS_CONNECTION_01_115: [If no more endpoints can be created due to all channels being used, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 4:98007eb79fa8 1675 if (connection->endpoint_count >= connection->channel_max)
AzureIoTClient 4:98007eb79fa8 1676 {
AzureIoTClient 4:98007eb79fa8 1677 result = NULL;
AzureIoTClient 4:98007eb79fa8 1678 }
AzureIoTClient 4:98007eb79fa8 1679 else
AzureIoTClient 4:98007eb79fa8 1680 {
AzureIoTClient 4:98007eb79fa8 1681 uint32_t i = 0;
Azure.IoT Build 0:6ae2f7bca550 1682
AzureIoTClient 4:98007eb79fa8 1683 /* Codes_SRS_CONNECTION_01_128: [The lowest number outgoing channel shall be associated with the newly created endpoint.] */
AzureIoTClient 4:98007eb79fa8 1684 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 1685 {
AzureIoTClient 4:98007eb79fa8 1686 if (connection->endpoints[i]->outgoing_channel > i)
AzureIoTClient 4:98007eb79fa8 1687 {
AzureIoTClient 4:98007eb79fa8 1688 /* found a gap in the sorted endpoint array */
AzureIoTClient 4:98007eb79fa8 1689 break;
AzureIoTClient 4:98007eb79fa8 1690 }
AzureIoTClient 4:98007eb79fa8 1691 }
Azure.IoT Build 0:6ae2f7bca550 1692
AzureIoTClient 4:98007eb79fa8 1693 /* Codes_SRS_CONNECTION_01_127: [On success, connection_create_endpoint shall return a non-NULL handle to the newly created endpoint.] */
AzureIoTClient 24:2c59c2d43ebf 1694 result = (ENDPOINT_HANDLE)malloc(sizeof(ENDPOINT_INSTANCE));
AzureIoTClient 4:98007eb79fa8 1695 /* Codes_SRS_CONNECTION_01_196: [If memory cannot be allocated for the new endpoint, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 28:add19eb7defa 1696 if (result == NULL)
AzureIoTClient 28:add19eb7defa 1697 {
AzureIoTClient 28:add19eb7defa 1698 LogError("Cannot allocate memory for endpoint");
AzureIoTClient 28:add19eb7defa 1699 }
AzureIoTClient 28:add19eb7defa 1700 else
AzureIoTClient 28:add19eb7defa 1701 {
AzureIoTClient 28:add19eb7defa 1702 ENDPOINT_HANDLE* new_endpoints;
Azure.IoT Build 0:6ae2f7bca550 1703
AzureIoTClient 4:98007eb79fa8 1704 result->on_endpoint_frame_received = NULL;
AzureIoTClient 4:98007eb79fa8 1705 result->on_connection_state_changed = NULL;
AzureIoTClient 4:98007eb79fa8 1706 result->callback_context = NULL;
AzureIoTClient 6:641a9672db08 1707 result->outgoing_channel = (uint16_t)i;
AzureIoTClient 4:98007eb79fa8 1708 result->connection = connection;
Azure.IoT Build 0:6ae2f7bca550 1709
AzureIoTClient 4:98007eb79fa8 1710 /* Codes_SRS_CONNECTION_01_197: [The newly created endpoint shall be added to the endpoints list, so that it can be tracked.] */
AzureIoTClient 24:2c59c2d43ebf 1711 new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, sizeof(ENDPOINT_HANDLE) * (connection->endpoint_count + 1));
AzureIoTClient 4:98007eb79fa8 1712 if (new_endpoints == NULL)
AzureIoTClient 4:98007eb79fa8 1713 {
AzureIoTClient 4:98007eb79fa8 1714 /* Tests_SRS_CONNECTION_01_198: [If adding the endpoint to the endpoints list tracked by the connection fails, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 28:add19eb7defa 1715 LogError("Cannot reallocate memory for connection endpoints");
AzureIoTClient 28:add19eb7defa 1716 free(result);
AzureIoTClient 4:98007eb79fa8 1717 result = NULL;
AzureIoTClient 4:98007eb79fa8 1718 }
AzureIoTClient 4:98007eb79fa8 1719 else
AzureIoTClient 4:98007eb79fa8 1720 {
AzureIoTClient 4:98007eb79fa8 1721 connection->endpoints = new_endpoints;
Azure.IoT Build 0:6ae2f7bca550 1722
AzureIoTClient 4:98007eb79fa8 1723 if (i < connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 1724 {
AzureIoTClient 4:98007eb79fa8 1725 (void)memmove(&connection->endpoints[i + 1], &connection->endpoints[i], sizeof(ENDPOINT_INSTANCE*) * (connection->endpoint_count - i));
AzureIoTClient 4:98007eb79fa8 1726 }
Azure.IoT Build 0:6ae2f7bca550 1727
AzureIoTClient 4:98007eb79fa8 1728 connection->endpoints[i] = result;
AzureIoTClient 4:98007eb79fa8 1729 connection->endpoint_count++;
Azure.IoT Build 0:6ae2f7bca550 1730
AzureIoTClient 4:98007eb79fa8 1731 /* Codes_SRS_CONNECTION_01_112: [connection_create_endpoint shall create a new endpoint that can be used by a session.] */
AzureIoTClient 4:98007eb79fa8 1732 }
AzureIoTClient 4:98007eb79fa8 1733 }
AzureIoTClient 4:98007eb79fa8 1734 }
AzureIoTClient 4:98007eb79fa8 1735 }
Azure.IoT Build 0:6ae2f7bca550 1736
AzureIoTClient 4:98007eb79fa8 1737 return result;
Azure.IoT Build 0:6ae2f7bca550 1738 }
Azure.IoT Build 0:6ae2f7bca550 1739
Azure.IoT Build 0:6ae2f7bca550 1740 int connection_start_endpoint(ENDPOINT_HANDLE endpoint, ON_ENDPOINT_FRAME_RECEIVED on_endpoint_frame_received, ON_CONNECTION_STATE_CHANGED on_connection_state_changed, void* context)
Azure.IoT Build 0:6ae2f7bca550 1741 {
AzureIoTClient 4:98007eb79fa8 1742 int result;
Azure.IoT Build 0:6ae2f7bca550 1743
AzureIoTClient 4:98007eb79fa8 1744 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1745 (on_endpoint_frame_received == NULL) ||
AzureIoTClient 4:98007eb79fa8 1746 (on_connection_state_changed == NULL))
AzureIoTClient 4:98007eb79fa8 1747 {
AzureIoTClient 28:add19eb7defa 1748 LogError("Bad arguments: endpoint = %p, on_endpoint_frame_received = %p, on_connection_state_changed = %p",
AzureIoTClient 28:add19eb7defa 1749 endpoint, on_endpoint_frame_received, on_connection_state_changed);
AzureIoTClient 28:add19eb7defa 1750 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1751 }
AzureIoTClient 4:98007eb79fa8 1752 else
AzureIoTClient 4:98007eb79fa8 1753 {
AzureIoTClient 4:98007eb79fa8 1754 endpoint->on_endpoint_frame_received = on_endpoint_frame_received;
AzureIoTClient 4:98007eb79fa8 1755 endpoint->on_connection_state_changed = on_connection_state_changed;
AzureIoTClient 4:98007eb79fa8 1756 endpoint->callback_context = context;
Azure.IoT Build 0:6ae2f7bca550 1757
AzureIoTClient 4:98007eb79fa8 1758 result = 0;
AzureIoTClient 4:98007eb79fa8 1759 }
Azure.IoT Build 0:6ae2f7bca550 1760
AzureIoTClient 4:98007eb79fa8 1761 return result;
Azure.IoT Build 0:6ae2f7bca550 1762 }
Azure.IoT Build 0:6ae2f7bca550 1763
Azure.IoT Build 0:6ae2f7bca550 1764 int connection_endpoint_get_incoming_channel(ENDPOINT_HANDLE endpoint, uint16_t* incoming_channel)
Azure.IoT Build 0:6ae2f7bca550 1765 {
AzureIoTClient 4:98007eb79fa8 1766 int result;
Azure.IoT Build 0:6ae2f7bca550 1767
AzureIoTClient 4:98007eb79fa8 1768 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1769 (incoming_channel == NULL))
AzureIoTClient 4:98007eb79fa8 1770 {
AzureIoTClient 28:add19eb7defa 1771 LogError("Bad arguments: endpoint = %p, incoming_channel = %p",
AzureIoTClient 28:add19eb7defa 1772 endpoint, incoming_channel);
AzureIoTClient 28:add19eb7defa 1773 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1774 }
AzureIoTClient 4:98007eb79fa8 1775 else
AzureIoTClient 4:98007eb79fa8 1776 {
AzureIoTClient 4:98007eb79fa8 1777 *incoming_channel = endpoint->incoming_channel;
AzureIoTClient 4:98007eb79fa8 1778 result = 0;
AzureIoTClient 4:98007eb79fa8 1779 }
Azure.IoT Build 0:6ae2f7bca550 1780
AzureIoTClient 4:98007eb79fa8 1781 return result;
Azure.IoT Build 0:6ae2f7bca550 1782 }
Azure.IoT Build 0:6ae2f7bca550 1783
Azure.IoT Build 0:6ae2f7bca550 1784 /* Codes_SRS_CONNECTION_01_129: [connection_destroy_endpoint shall free all resources associated with an endpoint created by connection_create_endpoint.] */
Azure.IoT Build 0:6ae2f7bca550 1785 void connection_destroy_endpoint(ENDPOINT_HANDLE endpoint)
Azure.IoT Build 0:6ae2f7bca550 1786 {
AzureIoTClient 28:add19eb7defa 1787 if (endpoint == NULL)
AzureIoTClient 28:add19eb7defa 1788 {
AzureIoTClient 28:add19eb7defa 1789 LogError("NULL endpoint");
AzureIoTClient 28:add19eb7defa 1790 }
AzureIoTClient 28:add19eb7defa 1791 else
AzureIoTClient 28:add19eb7defa 1792 {
AzureIoTClient 24:2c59c2d43ebf 1793 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)endpoint->connection;
AzureIoTClient 4:98007eb79fa8 1794 size_t i;
Azure.IoT Build 0:6ae2f7bca550 1795
AzureIoTClient 4:98007eb79fa8 1796 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 1797 {
AzureIoTClient 4:98007eb79fa8 1798 if (connection->endpoints[i] == endpoint)
AzureIoTClient 4:98007eb79fa8 1799 {
AzureIoTClient 4:98007eb79fa8 1800 break;
AzureIoTClient 4:98007eb79fa8 1801 }
AzureIoTClient 4:98007eb79fa8 1802 }
Azure.IoT Build 0:6ae2f7bca550 1803
AzureIoTClient 4:98007eb79fa8 1804 /* Codes_SRS_CONNECTION_01_130: [The outgoing channel associated with the endpoint shall be released by removing the endpoint from the endpoint list.] */
AzureIoTClient 4:98007eb79fa8 1805 /* Codes_SRS_CONNECTION_01_131: [Any incoming channel number associated with the endpoint shall be released.] */
AzureIoTClient 28:add19eb7defa 1806 if ((i < connection->endpoint_count) && (i > 0))
AzureIoTClient 28:add19eb7defa 1807 {
AzureIoTClient 28:add19eb7defa 1808 ENDPOINT_HANDLE* new_endpoints;
AzureIoTClient 28:add19eb7defa 1809 (void)memmove(connection->endpoints + i, connection->endpoints + i + 1, sizeof(ENDPOINT_HANDLE) * (connection->endpoint_count - i - 1));
Azure.IoT Build 0:6ae2f7bca550 1810
AzureIoTClient 28:add19eb7defa 1811 new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, (connection->endpoint_count - 1) * sizeof(ENDPOINT_HANDLE));
AzureIoTClient 28:add19eb7defa 1812 if (new_endpoints != NULL)
AzureIoTClient 28:add19eb7defa 1813 {
AzureIoTClient 28:add19eb7defa 1814 connection->endpoints = new_endpoints;
AzureIoTClient 28:add19eb7defa 1815 }
Azure.IoT Build 0:6ae2f7bca550 1816
AzureIoTClient 28:add19eb7defa 1817 connection->endpoint_count--;
AzureIoTClient 28:add19eb7defa 1818 }
AzureIoTClient 28:add19eb7defa 1819 else if (connection->endpoint_count == 1)
AzureIoTClient 28:add19eb7defa 1820 {
AzureIoTClient 28:add19eb7defa 1821 free(connection->endpoints);
AzureIoTClient 28:add19eb7defa 1822 connection->endpoints = NULL;
AzureIoTClient 28:add19eb7defa 1823 connection->endpoint_count = 0;
AzureIoTClient 28:add19eb7defa 1824 }
Azure.IoT Build 0:6ae2f7bca550 1825
AzureIoTClient 21:f9c433d8e6ca 1826 free(endpoint);
AzureIoTClient 4:98007eb79fa8 1827 }
Azure.IoT Build 0:6ae2f7bca550 1828 }
Azure.IoT Build 0:6ae2f7bca550 1829
Azure.IoT Build 0:6ae2f7bca550 1830 /* Codes_SRS_CONNECTION_01_247: [connection_encode_frame shall send a frame for a certain endpoint.] */
AzureIoTClient 30:0407b2db334c 1831 int connection_encode_frame(ENDPOINT_HANDLE endpoint, AMQP_VALUE performative, PAYLOAD* payloads, size_t payload_count, ON_SEND_COMPLETE on_send_complete, void* callback_context)
Azure.IoT Build 0:6ae2f7bca550 1832 {
AzureIoTClient 4:98007eb79fa8 1833 int result;
Azure.IoT Build 0:6ae2f7bca550 1834
AzureIoTClient 4:98007eb79fa8 1835 /* Codes_SRS_CONNECTION_01_249: [If endpoint or performative are NULL, connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1836 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1837 (performative == NULL))
AzureIoTClient 4:98007eb79fa8 1838 {
AzureIoTClient 28:add19eb7defa 1839 LogError("Bad arguments: endpoint = %p, performative = %p",
AzureIoTClient 28:add19eb7defa 1840 endpoint, performative);
AzureIoTClient 28:add19eb7defa 1841 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1842 }
AzureIoTClient 4:98007eb79fa8 1843 else
AzureIoTClient 4:98007eb79fa8 1844 {
AzureIoTClient 28:add19eb7defa 1845 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)endpoint->connection;
AzureIoTClient 4:98007eb79fa8 1846 AMQP_FRAME_CODEC_HANDLE amqp_frame_codec = connection->amqp_frame_codec;
Azure.IoT Build 0:6ae2f7bca550 1847
AzureIoTClient 4:98007eb79fa8 1848 /* Codes_SRS_CONNECTION_01_254: [If connection_encode_frame is called before the connection is in the OPENED state, connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1849 if (connection->connection_state != CONNECTION_STATE_OPENED)
AzureIoTClient 4:98007eb79fa8 1850 {
AzureIoTClient 28:add19eb7defa 1851 LogError("Connection not open");
AzureIoTClient 28:add19eb7defa 1852 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1853 }
AzureIoTClient 4:98007eb79fa8 1854 else
AzureIoTClient 4:98007eb79fa8 1855 {
AzureIoTClient 4:98007eb79fa8 1856 /* Codes_SRS_CONNECTION_01_255: [The payload size shall be computed based on all the payload chunks passed as argument in payloads.] */
AzureIoTClient 4:98007eb79fa8 1857 /* Codes_SRS_CONNECTION_01_250: [connection_encode_frame shall initiate the frame send by calling amqp_frame_codec_begin_encode_frame.] */
AzureIoTClient 4:98007eb79fa8 1858 /* Codes_SRS_CONNECTION_01_251: [The channel number passed to amqp_frame_codec_begin_encode_frame shall be the outgoing channel number associated with the endpoint by connection_create_endpoint.] */
AzureIoTClient 4:98007eb79fa8 1859 /* Codes_SRS_CONNECTION_01_252: [The performative passed to amqp_frame_codec_begin_encode_frame shall be the performative argument of connection_encode_frame.] */
AzureIoTClient 4:98007eb79fa8 1860 connection->on_send_complete = on_send_complete;
AzureIoTClient 4:98007eb79fa8 1861 connection->on_send_complete_callback_context = callback_context;
AzureIoTClient 4:98007eb79fa8 1862 if (amqp_frame_codec_encode_frame(amqp_frame_codec, endpoint->outgoing_channel, performative, payloads, payload_count, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 1863 {
AzureIoTClient 4:98007eb79fa8 1864 /* Codes_SRS_CONNECTION_01_253: [If amqp_frame_codec_begin_encode_frame or amqp_frame_codec_encode_payload_bytes fails, then connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1865 LogError("Encoding AMQP frame failed");
AzureIoTClient 28:add19eb7defa 1866 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1867 }
AzureIoTClient 4:98007eb79fa8 1868 else
AzureIoTClient 4:98007eb79fa8 1869 {
AzureIoTClient 4:98007eb79fa8 1870 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 1871 {
Azure.IoT Build 5:ae49385aff34 1872 log_outgoing_frame(performative);
AzureIoTClient 4:98007eb79fa8 1873 }
Azure.IoT Build 5:ae49385aff34 1874
AzureIoTClient 4:98007eb79fa8 1875 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_sent_time) != 0)
AzureIoTClient 4:98007eb79fa8 1876 {
AzureIoTClient 28:add19eb7defa 1877 LogError("Getting tick counter value failed");
AzureIoTClient 28:add19eb7defa 1878 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1879 }
AzureIoTClient 4:98007eb79fa8 1880 else
AzureIoTClient 4:98007eb79fa8 1881 {
AzureIoTClient 4:98007eb79fa8 1882 /* Codes_SRS_CONNECTION_01_248: [On success it shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1883 result = 0;
AzureIoTClient 4:98007eb79fa8 1884 }
AzureIoTClient 4:98007eb79fa8 1885 }
AzureIoTClient 4:98007eb79fa8 1886 }
AzureIoTClient 4:98007eb79fa8 1887 }
Azure.IoT Build 0:6ae2f7bca550 1888
AzureIoTClient 4:98007eb79fa8 1889 return result;
Azure.IoT Build 0:6ae2f7bca550 1890 }
AzureIoTClient 4:98007eb79fa8 1891
AzureIoTClient 24:2c59c2d43ebf 1892 void connection_set_trace(CONNECTION_HANDLE connection, bool trace_on)
AzureIoTClient 4:98007eb79fa8 1893 {
AzureIoTClient 4:98007eb79fa8 1894 /* Codes_SRS_CONNECTION_07_002: [If connection is NULL then connection_set_trace shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1895 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1896 {
AzureIoTClient 28:add19eb7defa 1897 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1898 }
AzureIoTClient 28:add19eb7defa 1899 else
AzureIoTClient 28:add19eb7defa 1900 {
AzureIoTClient 4:98007eb79fa8 1901 /* Codes_SRS_CONNECTION_07_001: [connection_set_trace shall set the ability to turn on and off trace logging.] */
AzureIoTClient 24:2c59c2d43ebf 1902 connection->is_trace_on = trace_on ? 1 : 0;
AzureIoTClient 4:98007eb79fa8 1903 }
AzureIoTClient 4:98007eb79fa8 1904 }
AzureIoTClient 35:d0bed2404ee9 1905
AzureIoTClient 35:d0bed2404ee9 1906 int connection_set_remote_idle_timeout_empty_frame_send_ratio(CONNECTION_HANDLE connection, double idle_timeout_empty_frame_send_ratio)
AzureIoTClient 35:d0bed2404ee9 1907 {
AzureIoTClient 35:d0bed2404ee9 1908 int result;
AzureIoTClient 35:d0bed2404ee9 1909
AzureIoTClient 35:d0bed2404ee9 1910 if ((connection == NULL) ||
AzureIoTClient 35:d0bed2404ee9 1911 (idle_timeout_empty_frame_send_ratio <= 0.0) ||
AzureIoTClient 35:d0bed2404ee9 1912 (idle_timeout_empty_frame_send_ratio > 1.0))
AzureIoTClient 35:d0bed2404ee9 1913 {
AzureIoTClient 35:d0bed2404ee9 1914 LogError("Bad arguments: connection = %p, idle_timeout_empty_frame_send_ratio = %f",
AzureIoTClient 35:d0bed2404ee9 1915 connection, idle_timeout_empty_frame_send_ratio);
AzureIoTClient 35:d0bed2404ee9 1916 result = __FAILURE__;
AzureIoTClient 35:d0bed2404ee9 1917 }
AzureIoTClient 35:d0bed2404ee9 1918 else
AzureIoTClient 35:d0bed2404ee9 1919 {
AzureIoTClient 35:d0bed2404ee9 1920 connection->idle_timeout_empty_frame_send_ratio = idle_timeout_empty_frame_send_ratio;
AzureIoTClient 35:d0bed2404ee9 1921 result = 0;
AzureIoTClient 35:d0bed2404ee9 1922 }
AzureIoTClient 35:d0bed2404ee9 1923
AzureIoTClient 35:d0bed2404ee9 1924 return result;
AzureIoTClient 35:d0bed2404ee9 1925 }