A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Committer:
AzureIoTClient
Date:
Thu Oct 04 09:16:13 2018 -0700
Revision:
47:365a93fdb5bb
Parent:
46:01f7ca900e07
1.2.10

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"
AzureIoTClient 41:0e723f9cbd89 15 #include "azure_uamqp_c/amqpvalue.h"
Azure.IoT Build 0:6ae2f7bca550 16 #include "azure_uamqp_c/amqp_frame_codec.h"
Azure.IoT Build 0:6ae2f7bca550 17 #include "azure_uamqp_c/amqp_definitions.h"
Azure.IoT Build 0:6ae2f7bca550 18 #include "azure_uamqp_c/amqpvalue_to_string.h"
Azure.IoT Build 0:6ae2f7bca550 19
Azure.IoT Build 0:6ae2f7bca550 20 /* Requirements satisfied by the virtue of implementing the ISO:*/
AzureIoTClient 43:4c1e4e94cdd3 21 /* Codes_S_R_S_CONNECTION_01_088: [Any data appearing beyond the protocol header MUST match the version indicated by the protocol header.] */
AzureIoTClient 43:4c1e4e94cdd3 22 /* Codes_S_R_S_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 23
AzureIoTClient 43:4c1e4e94cdd3 24 /* Codes_S_R_S_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 25 static const unsigned char amqp_header[] = { 'A', 'M', 'Q', 'P', 0, 1, 0, 0 };
Azure.IoT Build 0:6ae2f7bca550 26
Azure.IoT Build 0:6ae2f7bca550 27 typedef enum RECEIVE_FRAME_STATE_TAG
Azure.IoT Build 0:6ae2f7bca550 28 {
AzureIoTClient 4:98007eb79fa8 29 RECEIVE_FRAME_STATE_FRAME_SIZE,
AzureIoTClient 4:98007eb79fa8 30 RECEIVE_FRAME_STATE_FRAME_DATA
Azure.IoT Build 0:6ae2f7bca550 31 } RECEIVE_FRAME_STATE;
Azure.IoT Build 0:6ae2f7bca550 32
AzureIoTClient 43:4c1e4e94cdd3 33 typedef struct ON_CONNECTION_CLOSED_EVENT_SUBSCRIPTION_TAG
AzureIoTClient 43:4c1e4e94cdd3 34 {
AzureIoTClient 43:4c1e4e94cdd3 35 ON_CONNECTION_CLOSE_RECEIVED on_connection_close_received;
AzureIoTClient 43:4c1e4e94cdd3 36 void* context;
AzureIoTClient 43:4c1e4e94cdd3 37 } ON_CONNECTION_CLOSED_EVENT_SUBSCRIPTION;
AzureIoTClient 43:4c1e4e94cdd3 38
Azure.IoT Build 0:6ae2f7bca550 39 typedef struct ENDPOINT_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 40 {
AzureIoTClient 4:98007eb79fa8 41 uint16_t incoming_channel;
AzureIoTClient 4:98007eb79fa8 42 uint16_t outgoing_channel;
AzureIoTClient 4:98007eb79fa8 43 ON_ENDPOINT_FRAME_RECEIVED on_endpoint_frame_received;
AzureIoTClient 4:98007eb79fa8 44 ON_CONNECTION_STATE_CHANGED on_connection_state_changed;
AzureIoTClient 4:98007eb79fa8 45 void* callback_context;
AzureIoTClient 4:98007eb79fa8 46 CONNECTION_HANDLE connection;
Azure.IoT Build 0:6ae2f7bca550 47 } ENDPOINT_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 48
Azure.IoT Build 0:6ae2f7bca550 49 typedef struct CONNECTION_INSTANCE_TAG
Azure.IoT Build 0:6ae2f7bca550 50 {
AzureIoTClient 4:98007eb79fa8 51 XIO_HANDLE io;
AzureIoTClient 4:98007eb79fa8 52 size_t header_bytes_received;
AzureIoTClient 4:98007eb79fa8 53 CONNECTION_STATE connection_state;
AzureIoTClient 4:98007eb79fa8 54 FRAME_CODEC_HANDLE frame_codec;
AzureIoTClient 4:98007eb79fa8 55 AMQP_FRAME_CODEC_HANDLE amqp_frame_codec;
AzureIoTClient 4:98007eb79fa8 56 ENDPOINT_INSTANCE** endpoints;
AzureIoTClient 4:98007eb79fa8 57 uint32_t endpoint_count;
AzureIoTClient 4:98007eb79fa8 58 char* host_name;
AzureIoTClient 4:98007eb79fa8 59 char* container_id;
AzureIoTClient 4:98007eb79fa8 60 TICK_COUNTER_HANDLE tick_counter;
AzureIoTClient 4:98007eb79fa8 61 uint32_t remote_max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 62
AzureIoTClient 4:98007eb79fa8 63 ON_SEND_COMPLETE on_send_complete;
AzureIoTClient 4:98007eb79fa8 64 void* on_send_complete_callback_context;
Azure.IoT Build 0:6ae2f7bca550 65
AzureIoTClient 4:98007eb79fa8 66 ON_NEW_ENDPOINT on_new_endpoint;
AzureIoTClient 4:98007eb79fa8 67 void* on_new_endpoint_callback_context;
Azure.IoT Build 0:6ae2f7bca550 68
Azure.IoT Build 0:6ae2f7bca550 69 ON_CONNECTION_STATE_CHANGED on_connection_state_changed;
Azure.IoT Build 0:6ae2f7bca550 70 void* on_connection_state_changed_callback_context;
Azure.IoT Build 0:6ae2f7bca550 71 ON_IO_ERROR on_io_error;
Azure.IoT Build 0:6ae2f7bca550 72 void* on_io_error_callback_context;
Azure.IoT Build 0:6ae2f7bca550 73
AzureIoTClient 43:4c1e4e94cdd3 74 ON_CONNECTION_CLOSED_EVENT_SUBSCRIPTION on_connection_close_received_event_subscription;
AzureIoTClient 43:4c1e4e94cdd3 75
AzureIoTClient 4:98007eb79fa8 76 /* options */
AzureIoTClient 4:98007eb79fa8 77 uint32_t max_frame_size;
AzureIoTClient 4:98007eb79fa8 78 uint16_t channel_max;
AzureIoTClient 4:98007eb79fa8 79 milliseconds idle_timeout;
AzureIoTClient 4:98007eb79fa8 80 milliseconds remote_idle_timeout;
AzureIoTClient 35:d0bed2404ee9 81 milliseconds remote_idle_timeout_send_frame_millisecond;
AzureIoTClient 35:d0bed2404ee9 82 double idle_timeout_empty_frame_send_ratio;
Azure.IoT.Build 14:0b0e28c75ded 83 tickcounter_ms_t last_frame_received_time;
Azure.IoT.Build 14:0b0e28c75ded 84 tickcounter_ms_t last_frame_sent_time;
AzureIoTClient 41:0e723f9cbd89 85 fields properties;
Azure.IoT Build 0:6ae2f7bca550 86
AzureIoTClient 4:98007eb79fa8 87 unsigned int is_underlying_io_open : 1;
AzureIoTClient 4:98007eb79fa8 88 unsigned int idle_timeout_specified : 1;
AzureIoTClient 4:98007eb79fa8 89 unsigned int is_remote_frame_received : 1;
AzureIoTClient 4:98007eb79fa8 90 unsigned int is_trace_on : 1;
Azure.IoT Build 0:6ae2f7bca550 91 } CONNECTION_INSTANCE;
Azure.IoT Build 0:6ae2f7bca550 92
AzureIoTClient 43:4c1e4e94cdd3 93 /* Codes_S_R_S_CONNECTION_01_258: [on_connection_state_changed shall be invoked whenever the connection state changes.]*/
AzureIoTClient 24:2c59c2d43ebf 94 static void connection_set_state(CONNECTION_HANDLE connection, CONNECTION_STATE connection_state)
Azure.IoT Build 0:6ae2f7bca550 95 {
AzureIoTClient 4:98007eb79fa8 96 uint64_t i;
Azure.IoT Build 0:6ae2f7bca550 97
AzureIoTClient 24:2c59c2d43ebf 98 CONNECTION_STATE previous_state = connection->connection_state;
AzureIoTClient 24:2c59c2d43ebf 99 connection->connection_state = connection_state;
Azure.IoT Build 0:6ae2f7bca550 100
AzureIoTClient 43:4c1e4e94cdd3 101 /* Codes_S_R_S_CONNECTION_22_001: [If a connection state changed occurs and a callback is registered the callback shall be called.] */
AzureIoTClient 24:2c59c2d43ebf 102 if (connection->on_connection_state_changed)
Azure.IoT Build 0:6ae2f7bca550 103 {
AzureIoTClient 24:2c59c2d43ebf 104 connection->on_connection_state_changed(connection->on_connection_state_changed_callback_context, connection_state, previous_state);
Azure.IoT Build 0:6ae2f7bca550 105 }
Azure.IoT Build 0:6ae2f7bca550 106
AzureIoTClient 43:4c1e4e94cdd3 107 /* Codes_S_R_S_CONNECTION_01_260: [Each endpoint's on_connection_state_changed shall be called.] */
AzureIoTClient 24:2c59c2d43ebf 108 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 109 {
AzureIoTClient 43:4c1e4e94cdd3 110 /* Codes_S_R_S_CONNECTION_01_259: [The callback_context passed in connection_create_endpoint.] */
AzureIoTClient 43:4c1e4e94cdd3 111 if (connection->endpoints[i]->on_connection_state_changed != NULL)
AzureIoTClient 43:4c1e4e94cdd3 112 {
AzureIoTClient 43:4c1e4e94cdd3 113 connection->endpoints[i]->on_connection_state_changed(connection->endpoints[i]->callback_context, connection_state, previous_state);
AzureIoTClient 43:4c1e4e94cdd3 114 }
AzureIoTClient 4:98007eb79fa8 115 }
Azure.IoT Build 0:6ae2f7bca550 116 }
Azure.IoT Build 0:6ae2f7bca550 117
AzureIoTClient 43:4c1e4e94cdd3 118 // This callback usage needs to be either verified and commented or integrated into
AzureIoTClient 38:7631b92cc772 119 // the state machine.
AzureIoTClient 38:7631b92cc772 120 static void unchecked_on_send_complete(void* context, IO_SEND_RESULT send_result)
AzureIoTClient 38:7631b92cc772 121 {
AzureIoTClient 38:7631b92cc772 122 (void)context;
AzureIoTClient 38:7631b92cc772 123 (void)send_result;
AzureIoTClient 38:7631b92cc772 124 }
AzureIoTClient 38:7631b92cc772 125
AzureIoTClient 24:2c59c2d43ebf 126 static int send_header(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 127 {
AzureIoTClient 4:98007eb79fa8 128 int result;
Azure.IoT Build 0:6ae2f7bca550 129
AzureIoTClient 43:4c1e4e94cdd3 130 /* Codes_S_R_S_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 43:4c1e4e94cdd3 131 /* Codes_S_R_S_CONNECTION_01_104: [Sending the protocol header shall be done by using xio_send.] */
AzureIoTClient 38:7631b92cc772 132 if (xio_send(connection->io, amqp_header, sizeof(amqp_header), unchecked_on_send_complete, NULL) != 0)
AzureIoTClient 4:98007eb79fa8 133 {
AzureIoTClient 43:4c1e4e94cdd3 134 /* Codes_S_R_S_CONNECTION_01_106: [When sending the protocol header fails, the connection shall be immediately closed.] */
AzureIoTClient 28:add19eb7defa 135 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 136 {
AzureIoTClient 28:add19eb7defa 137 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 138 }
Azure.IoT Build 0:6ae2f7bca550 139
AzureIoTClient 43:4c1e4e94cdd3 140 /* Codes_S_R_S_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 141 connection_set_state(connection, CONNECTION_STATE_END);
Azure.IoT Build 0:6ae2f7bca550 142
AzureIoTClient 43:4c1e4e94cdd3 143 /* Codes_S_R_S_CONNECTION_01_105: [When xio_send fails, connection_dowork shall return a non-zero value.] */
AzureIoTClient 19:000ab4e6a2c1 144 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 145 }
AzureIoTClient 4:98007eb79fa8 146 else
AzureIoTClient 4:98007eb79fa8 147 {
AzureIoTClient 24:2c59c2d43ebf 148 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 149 {
AzureIoTClient 16:22a72cf8e416 150 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Header (AMQP 0.1.0.0)");
AzureIoTClient 4:98007eb79fa8 151 }
Azure.IoT Build 0:6ae2f7bca550 152
AzureIoTClient 43:4c1e4e94cdd3 153 /* Codes_S_R_S_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 154 connection_set_state(connection, CONNECTION_STATE_HDR_SENT);
AzureIoTClient 4:98007eb79fa8 155 result = 0;
AzureIoTClient 4:98007eb79fa8 156 }
Azure.IoT Build 0:6ae2f7bca550 157
AzureIoTClient 4:98007eb79fa8 158 return result;
Azure.IoT Build 0:6ae2f7bca550 159 }
Azure.IoT Build 0:6ae2f7bca550 160
AzureIoTClient 43:4c1e4e94cdd3 161 #ifndef NO_LOGGING
Azure.IoT Build 0:6ae2f7bca550 162 static const char* get_frame_type_as_string(AMQP_VALUE descriptor)
Azure.IoT Build 0:6ae2f7bca550 163 {
AzureIoTClient 4:98007eb79fa8 164 const char* result;
Azure.IoT Build 0:6ae2f7bca550 165
AzureIoTClient 4:98007eb79fa8 166 if (is_open_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 167 {
AzureIoTClient 4:98007eb79fa8 168 result = "[OPEN]";
AzureIoTClient 4:98007eb79fa8 169 }
AzureIoTClient 4:98007eb79fa8 170 else if (is_begin_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 171 {
AzureIoTClient 4:98007eb79fa8 172 result = "[BEGIN]";
AzureIoTClient 4:98007eb79fa8 173 }
AzureIoTClient 4:98007eb79fa8 174 else if (is_attach_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 175 {
AzureIoTClient 4:98007eb79fa8 176 result = "[ATTACH]";
AzureIoTClient 4:98007eb79fa8 177 }
AzureIoTClient 4:98007eb79fa8 178 else if (is_flow_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 179 {
AzureIoTClient 4:98007eb79fa8 180 result = "[FLOW]";
AzureIoTClient 4:98007eb79fa8 181 }
AzureIoTClient 4:98007eb79fa8 182 else if (is_disposition_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 183 {
AzureIoTClient 4:98007eb79fa8 184 result = "[DISPOSITION]";
AzureIoTClient 4:98007eb79fa8 185 }
AzureIoTClient 4:98007eb79fa8 186 else if (is_transfer_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 187 {
AzureIoTClient 4:98007eb79fa8 188 result = "[TRANSFER]";
AzureIoTClient 4:98007eb79fa8 189 }
AzureIoTClient 4:98007eb79fa8 190 else if (is_detach_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 191 {
AzureIoTClient 4:98007eb79fa8 192 result = "[DETACH]";
AzureIoTClient 4:98007eb79fa8 193 }
AzureIoTClient 4:98007eb79fa8 194 else if (is_end_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 195 {
AzureIoTClient 4:98007eb79fa8 196 result = "[END]";
AzureIoTClient 4:98007eb79fa8 197 }
AzureIoTClient 4:98007eb79fa8 198 else if (is_close_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 199 {
AzureIoTClient 4:98007eb79fa8 200 result = "[CLOSE]";
AzureIoTClient 4:98007eb79fa8 201 }
AzureIoTClient 4:98007eb79fa8 202 else
AzureIoTClient 4:98007eb79fa8 203 {
AzureIoTClient 4:98007eb79fa8 204 result = "[Unknown]";
AzureIoTClient 4:98007eb79fa8 205 }
Azure.IoT Build 0:6ae2f7bca550 206
AzureIoTClient 4:98007eb79fa8 207 return result;
Azure.IoT Build 0:6ae2f7bca550 208 }
AzureIoTClient 43:4c1e4e94cdd3 209 #endif // NO_LOGGING
Azure.IoT Build 0:6ae2f7bca550 210
Azure.IoT Build 5:ae49385aff34 211 static void log_incoming_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 212 {
AzureIoTClient 9:c22db038556c 213 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 214 UNUSED(performative);
AzureIoTClient 9:c22db038556c 215 #else
AzureIoTClient 4:98007eb79fa8 216 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 28:add19eb7defa 217 if (descriptor == NULL)
AzureIoTClient 28:add19eb7defa 218 {
AzureIoTClient 28:add19eb7defa 219 LogError("Error getting performative descriptor");
AzureIoTClient 28:add19eb7defa 220 }
AzureIoTClient 28:add19eb7defa 221 else
AzureIoTClient 28:add19eb7defa 222 {
AzureIoTClient 28:add19eb7defa 223 char* performative_as_string;
AzureIoTClient 16:22a72cf8e416 224 LOG(AZ_LOG_TRACE, 0, "<- ");
AzureIoTClient 16:22a72cf8e416 225 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 226 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 227 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 4:98007eb79fa8 228 if (performative_as_string != NULL)
AzureIoTClient 4:98007eb79fa8 229 {
AzureIoTClient 21:f9c433d8e6ca 230 free(performative_as_string);
AzureIoTClient 4:98007eb79fa8 231 }
AzureIoTClient 4:98007eb79fa8 232 }
AzureIoTClient 9:c22db038556c 233 #endif
Azure.IoT Build 0:6ae2f7bca550 234 }
Azure.IoT Build 0:6ae2f7bca550 235
Azure.IoT Build 5:ae49385aff34 236 static void log_outgoing_frame(AMQP_VALUE performative)
Azure.IoT Build 0:6ae2f7bca550 237 {
AzureIoTClient 9:c22db038556c 238 #ifdef NO_LOGGING
AzureIoTClient 9:c22db038556c 239 UNUSED(performative);
AzureIoTClient 9:c22db038556c 240 #else
AzureIoTClient 4:98007eb79fa8 241 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
AzureIoTClient 28:add19eb7defa 242 if (descriptor == NULL)
AzureIoTClient 28:add19eb7defa 243 {
AzureIoTClient 28:add19eb7defa 244 LogError("Error getting performative descriptor");
AzureIoTClient 28:add19eb7defa 245 }
AzureIoTClient 28:add19eb7defa 246 else
AzureIoTClient 28:add19eb7defa 247 {
AzureIoTClient 28:add19eb7defa 248 char* performative_as_string;
AzureIoTClient 28:add19eb7defa 249 LOG(AZ_LOG_TRACE, 0, "-> ");
AzureIoTClient 16:22a72cf8e416 250 LOG(AZ_LOG_TRACE, 0, (char*)get_frame_type_as_string(descriptor));
AzureIoTClient 25:1101516ee67d 251 performative_as_string = NULL;
AzureIoTClient 16:22a72cf8e416 252 LOG(AZ_LOG_TRACE, LOG_LINE, (performative_as_string = amqpvalue_to_string(performative)));
AzureIoTClient 4:98007eb79fa8 253 if (performative_as_string != NULL)
AzureIoTClient 4:98007eb79fa8 254 {
AzureIoTClient 21:f9c433d8e6ca 255 free(performative_as_string);
AzureIoTClient 4:98007eb79fa8 256 }
AzureIoTClient 4:98007eb79fa8 257 }
AzureIoTClient 9:c22db038556c 258 #endif
Azure.IoT Build 0:6ae2f7bca550 259 }
Azure.IoT Build 0:6ae2f7bca550 260
Azure.IoT Build 0:6ae2f7bca550 261 static void on_bytes_encoded(void* context, const unsigned char* bytes, size_t length, bool encode_complete)
Azure.IoT Build 0:6ae2f7bca550 262 {
AzureIoTClient 24:2c59c2d43ebf 263 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 43:4c1e4e94cdd3 264 if (xio_send(connection->io, bytes, length,
AzureIoTClient 38:7631b92cc772 265 (encode_complete && connection->on_send_complete != NULL) ? connection->on_send_complete : unchecked_on_send_complete,
AzureIoTClient 38:7631b92cc772 266 connection->on_send_complete_callback_context) != 0)
AzureIoTClient 4:98007eb79fa8 267 {
AzureIoTClient 28:add19eb7defa 268 LogError("Cannot send encoded bytes");
AzureIoTClient 24:2c59c2d43ebf 269
AzureIoTClient 28:add19eb7defa 270 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 271 {
AzureIoTClient 28:add19eb7defa 272 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 273 }
AzureIoTClient 24:2c59c2d43ebf 274
AzureIoTClient 24:2c59c2d43ebf 275 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 276 }
Azure.IoT Build 0:6ae2f7bca550 277 }
Azure.IoT Build 0:6ae2f7bca550 278
AzureIoTClient 24:2c59c2d43ebf 279 static int send_open_frame(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 280 {
AzureIoTClient 4:98007eb79fa8 281 int result;
Azure.IoT Build 0:6ae2f7bca550 282
AzureIoTClient 43:4c1e4e94cdd3 283 /* Codes_S_R_S_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 284 if (frame_codec_set_max_frame_size(connection->frame_codec, connection->max_frame_size) != 0)
AzureIoTClient 4:98007eb79fa8 285 {
AzureIoTClient 28:add19eb7defa 286 LogError("Cannot set max frame size");
AzureIoTClient 24:2c59c2d43ebf 287
AzureIoTClient 43:4c1e4e94cdd3 288 /* Codes_S_R_S_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 289 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 290 {
AzureIoTClient 28:add19eb7defa 291 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 292 }
AzureIoTClient 24:2c59c2d43ebf 293
AzureIoTClient 28:add19eb7defa 294 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 295 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 296 }
AzureIoTClient 4:98007eb79fa8 297 else
AzureIoTClient 4:98007eb79fa8 298 {
AzureIoTClient 43:4c1e4e94cdd3 299 /* Codes_S_R_S_CONNECTION_01_134: [The container id field shall be filled with the container id specified in connection_create.] */
AzureIoTClient 24:2c59c2d43ebf 300 OPEN_HANDLE open_performative = open_create(connection->container_id);
AzureIoTClient 4:98007eb79fa8 301 if (open_performative == NULL)
AzureIoTClient 4:98007eb79fa8 302 {
AzureIoTClient 28:add19eb7defa 303 LogError("Cannot create OPEN performative");
AzureIoTClient 43:4c1e4e94cdd3 304
AzureIoTClient 43:4c1e4e94cdd3 305 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 306 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 307 {
AzureIoTClient 28:add19eb7defa 308 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 309 }
AzureIoTClient 24:2c59c2d43ebf 310
AzureIoTClient 28:add19eb7defa 311 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 312 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 313 }
AzureIoTClient 4:98007eb79fa8 314 else
AzureIoTClient 4:98007eb79fa8 315 {
AzureIoTClient 43:4c1e4e94cdd3 316 /* Codes_S_R_S_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 317 if (open_set_max_frame_size(open_performative, connection->max_frame_size) != 0)
AzureIoTClient 4:98007eb79fa8 318 {
AzureIoTClient 28:add19eb7defa 319 LogError("Cannot set max frame size");
AzureIoTClient 24:2c59c2d43ebf 320
AzureIoTClient 43:4c1e4e94cdd3 321 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 322 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 323 {
AzureIoTClient 28:add19eb7defa 324 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 325 }
AzureIoTClient 24:2c59c2d43ebf 326
AzureIoTClient 28:add19eb7defa 327 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 328 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 329 }
AzureIoTClient 43:4c1e4e94cdd3 330 /* Codes_S_R_S_CONNECTION_01_139: [The channel_max connection setting shall be set in the open frame by using open_set_channel_max.] */
AzureIoTClient 24:2c59c2d43ebf 331 else if (open_set_channel_max(open_performative, connection->channel_max) != 0)
AzureIoTClient 4:98007eb79fa8 332 {
AzureIoTClient 28:add19eb7defa 333 LogError("Cannot set max channel");
AzureIoTClient 24:2c59c2d43ebf 334
AzureIoTClient 43:4c1e4e94cdd3 335 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 336 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 337 {
AzureIoTClient 28:add19eb7defa 338 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 339 }
AzureIoTClient 24:2c59c2d43ebf 340
AzureIoTClient 28:add19eb7defa 341 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 342 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 343 }
AzureIoTClient 43:4c1e4e94cdd3 344 /* Codes_S_R_S_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 345 else if ((connection->idle_timeout_specified) &&
AzureIoTClient 43:4c1e4e94cdd3 346 /* Codes_S_R_S_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 347 (open_set_idle_time_out(open_performative, connection->idle_timeout) != 0))
AzureIoTClient 4:98007eb79fa8 348 {
AzureIoTClient 43:4c1e4e94cdd3 349 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 350 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 351 {
AzureIoTClient 28:add19eb7defa 352 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 353 }
AzureIoTClient 24:2c59c2d43ebf 354
AzureIoTClient 28:add19eb7defa 355 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 356 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 357 }
AzureIoTClient 43:4c1e4e94cdd3 358 /* Codes_S_R_S_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 359 else if ((connection->host_name != NULL) &&
AzureIoTClient 43:4c1e4e94cdd3 360 /* Codes_S_R_S_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 361 (open_set_hostname(open_performative, connection->host_name) != 0))
AzureIoTClient 4:98007eb79fa8 362 {
AzureIoTClient 28:add19eb7defa 363 LogError("Cannot set hostname");
AzureIoTClient 24:2c59c2d43ebf 364
AzureIoTClient 43:4c1e4e94cdd3 365 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 366 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 367 {
AzureIoTClient 28:add19eb7defa 368 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 369 }
AzureIoTClient 24:2c59c2d43ebf 370
AzureIoTClient 28:add19eb7defa 371 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 372 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 373 }
AzureIoTClient 43:4c1e4e94cdd3 374 /* Codes_S_R_S_CONNECTION_01_243: [If no properties value has been specified, no value shall be stamped in the open frame (no call to open_set_properties shall be made).] */
AzureIoTClient 41:0e723f9cbd89 375 else if ((connection->properties != NULL) &&
AzureIoTClient 43:4c1e4e94cdd3 376 /* Codes_S_R_S_CONNECTION_01_244: [If properties has been specified by a call to connection_set_properties, then that value shall be stamped in the open frame.] */
AzureIoTClient 41:0e723f9cbd89 377 (open_set_properties(open_performative, connection->properties) != 0))
AzureIoTClient 41:0e723f9cbd89 378 {
AzureIoTClient 41:0e723f9cbd89 379 LogError("Cannot set properties");
AzureIoTClient 41:0e723f9cbd89 380
AzureIoTClient 43:4c1e4e94cdd3 381 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 41:0e723f9cbd89 382 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 41:0e723f9cbd89 383 {
AzureIoTClient 41:0e723f9cbd89 384 LogError("xio_close failed");
AzureIoTClient 41:0e723f9cbd89 385 }
AzureIoTClient 41:0e723f9cbd89 386
AzureIoTClient 41:0e723f9cbd89 387 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 41:0e723f9cbd89 388 result = __FAILURE__;
AzureIoTClient 41:0e723f9cbd89 389 }
AzureIoTClient 4:98007eb79fa8 390 else
AzureIoTClient 4:98007eb79fa8 391 {
AzureIoTClient 4:98007eb79fa8 392 AMQP_VALUE open_performative_value = amqpvalue_create_open(open_performative);
AzureIoTClient 4:98007eb79fa8 393 if (open_performative_value == NULL)
AzureIoTClient 4:98007eb79fa8 394 {
AzureIoTClient 28:add19eb7defa 395 LogError("Cannot create OPEN AMQP value");
AzureIoTClient 24:2c59c2d43ebf 396
AzureIoTClient 43:4c1e4e94cdd3 397 /* Codes_S_R_S_CONNECTION_01_208: [If the open frame cannot be constructed, the connection shall be closed and set to the END state.] */
AzureIoTClient 28:add19eb7defa 398 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 399 {
AzureIoTClient 28:add19eb7defa 400 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 401 }
AzureIoTClient 24:2c59c2d43ebf 402
AzureIoTClient 28:add19eb7defa 403 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 404 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 405 }
AzureIoTClient 4:98007eb79fa8 406 else
AzureIoTClient 4:98007eb79fa8 407 {
AzureIoTClient 43:4c1e4e94cdd3 408 /* Codes_S_R_S_CONNECTION_01_002: [Each AMQP connection begins with an exchange of capabilities and limitations, including the maximum frame size.] */
AzureIoTClient 43:4c1e4e94cdd3 409 /* Codes_S_R_S_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 43:4c1e4e94cdd3 410 /* Codes_S_R_S_CONNECTION_01_005: [The open frame describes the capabilities and limits of that peer.] */
AzureIoTClient 43:4c1e4e94cdd3 411 /* Codes_S_R_S_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 43:4c1e4e94cdd3 412 /* Codes_S_R_S_CONNECTION_01_006: [The open frame can only be sent on channel 0.] */
AzureIoTClient 28:add19eb7defa 413 connection->on_send_complete = NULL;
AzureIoTClient 28:add19eb7defa 414 connection->on_send_complete_callback_context = NULL;
AzureIoTClient 24:2c59c2d43ebf 415 if (amqp_frame_codec_encode_frame(connection->amqp_frame_codec, 0, open_performative_value, NULL, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 416 {
AzureIoTClient 28:add19eb7defa 417 LogError("amqp_frame_codec_encode_frame failed");
AzureIoTClient 24:2c59c2d43ebf 418
AzureIoTClient 43:4c1e4e94cdd3 419 /* Codes_S_R_S_CONNECTION_01_206: [If sending the frame fails, the connection shall be closed and state set to END.] */
AzureIoTClient 28:add19eb7defa 420 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 421 {
AzureIoTClient 28:add19eb7defa 422 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 423 }
AzureIoTClient 24:2c59c2d43ebf 424
AzureIoTClient 28:add19eb7defa 425 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 426 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 427 }
AzureIoTClient 4:98007eb79fa8 428 else
AzureIoTClient 4:98007eb79fa8 429 {
AzureIoTClient 24:2c59c2d43ebf 430 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 431 {
Azure.IoT Build 5:ae49385aff34 432 log_outgoing_frame(open_performative_value);
AzureIoTClient 4:98007eb79fa8 433 }
Azure.IoT Build 0:6ae2f7bca550 434
AzureIoTClient 43:4c1e4e94cdd3 435 /* Codes_S_R_S_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 436 connection_set_state(connection, CONNECTION_STATE_OPEN_SENT);
AzureIoTClient 4:98007eb79fa8 437 result = 0;
AzureIoTClient 4:98007eb79fa8 438 }
Azure.IoT Build 0:6ae2f7bca550 439
AzureIoTClient 4:98007eb79fa8 440 amqpvalue_destroy(open_performative_value);
AzureIoTClient 4:98007eb79fa8 441 }
AzureIoTClient 4:98007eb79fa8 442 }
Azure.IoT Build 0:6ae2f7bca550 443
AzureIoTClient 4:98007eb79fa8 444 open_destroy(open_performative);
AzureIoTClient 4:98007eb79fa8 445 }
AzureIoTClient 4:98007eb79fa8 446 }
Azure.IoT Build 0:6ae2f7bca550 447
AzureIoTClient 4:98007eb79fa8 448 return result;
Azure.IoT Build 0:6ae2f7bca550 449 }
Azure.IoT Build 0:6ae2f7bca550 450
AzureIoTClient 24:2c59c2d43ebf 451 static int send_close_frame(CONNECTION_HANDLE connection, ERROR_HANDLE error_handle)
Azure.IoT Build 0:6ae2f7bca550 452 {
AzureIoTClient 4:98007eb79fa8 453 int result;
AzureIoTClient 4:98007eb79fa8 454 CLOSE_HANDLE close_performative;
Azure.IoT Build 0:6ae2f7bca550 455
AzureIoTClient 43:4c1e4e94cdd3 456 /* Codes_S_R_S_CONNECTION_01_217: [The CLOSE frame shall be constructed by using close_create.] */
AzureIoTClient 4:98007eb79fa8 457 close_performative = close_create();
AzureIoTClient 4:98007eb79fa8 458 if (close_performative == NULL)
AzureIoTClient 4:98007eb79fa8 459 {
AzureIoTClient 28:add19eb7defa 460 LogError("Cannot create close performative");
AzureIoTClient 28:add19eb7defa 461 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 462 }
AzureIoTClient 4:98007eb79fa8 463 else
AzureIoTClient 4:98007eb79fa8 464 {
AzureIoTClient 4:98007eb79fa8 465 if ((error_handle != NULL) &&
AzureIoTClient 43:4c1e4e94cdd3 466 /* Codes_S_R_S_CONNECTION_01_238: [If set, this field indicates that the connection is being closed due to an error condition.] */
AzureIoTClient 4:98007eb79fa8 467 (close_set_error(close_performative, error_handle) != 0))
AzureIoTClient 4:98007eb79fa8 468 {
AzureIoTClient 28:add19eb7defa 469 LogError("Cannot set error on CLOSE");
AzureIoTClient 28:add19eb7defa 470 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 471 }
AzureIoTClient 4:98007eb79fa8 472 else
AzureIoTClient 4:98007eb79fa8 473 {
AzureIoTClient 4:98007eb79fa8 474 AMQP_VALUE close_performative_value = amqpvalue_create_close(close_performative);
AzureIoTClient 4:98007eb79fa8 475 if (close_performative_value == NULL)
AzureIoTClient 4:98007eb79fa8 476 {
AzureIoTClient 28:add19eb7defa 477 LogError("Cannot create AMQP CLOSE performative value");
AzureIoTClient 28:add19eb7defa 478 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 479 }
AzureIoTClient 4:98007eb79fa8 480 else
AzureIoTClient 4:98007eb79fa8 481 {
AzureIoTClient 43:4c1e4e94cdd3 482 /* Codes_S_R_S_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 43:4c1e4e94cdd3 483 /* Codes_S_R_S_CONNECTION_01_013: [However, implementations SHOULD send it on channel 0] */
AzureIoTClient 28:add19eb7defa 484 connection->on_send_complete = NULL;
AzureIoTClient 28:add19eb7defa 485 connection->on_send_complete_callback_context = NULL;
AzureIoTClient 24:2c59c2d43ebf 486 if (amqp_frame_codec_encode_frame(connection->amqp_frame_codec, 0, close_performative_value, NULL, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 487 {
AzureIoTClient 28:add19eb7defa 488 LogError("amqp_frame_codec_encode_frame failed");
AzureIoTClient 28:add19eb7defa 489 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 490 }
AzureIoTClient 4:98007eb79fa8 491 else
AzureIoTClient 4:98007eb79fa8 492 {
AzureIoTClient 24:2c59c2d43ebf 493 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 494 {
Azure.IoT Build 5:ae49385aff34 495 log_outgoing_frame(close_performative_value);
AzureIoTClient 4:98007eb79fa8 496 }
Azure.IoT Build 5:ae49385aff34 497
AzureIoTClient 4:98007eb79fa8 498 result = 0;
AzureIoTClient 4:98007eb79fa8 499 }
Azure.IoT Build 0:6ae2f7bca550 500
AzureIoTClient 4:98007eb79fa8 501 amqpvalue_destroy(close_performative_value);
AzureIoTClient 4:98007eb79fa8 502 }
AzureIoTClient 4:98007eb79fa8 503 }
Azure.IoT Build 0:6ae2f7bca550 504
AzureIoTClient 4:98007eb79fa8 505 close_destroy(close_performative);
AzureIoTClient 4:98007eb79fa8 506 }
Azure.IoT Build 0:6ae2f7bca550 507
AzureIoTClient 4:98007eb79fa8 508 return result;
Azure.IoT Build 0:6ae2f7bca550 509 }
Azure.IoT Build 0:6ae2f7bca550 510
AzureIoTClient 43:4c1e4e94cdd3 511 static void close_connection_with_error(CONNECTION_HANDLE connection, const char* condition_value, const char* description, AMQP_VALUE info)
Azure.IoT Build 0:6ae2f7bca550 512 {
AzureIoTClient 4:98007eb79fa8 513 ERROR_HANDLE error_handle = error_create(condition_value);
AzureIoTClient 43:4c1e4e94cdd3 514
AzureIoTClient 4:98007eb79fa8 515 if (error_handle == NULL)
AzureIoTClient 4:98007eb79fa8 516 {
AzureIoTClient 43:4c1e4e94cdd3 517 /* Codes_S_R_S_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 518 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 519 {
AzureIoTClient 28:add19eb7defa 520 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 521 }
AzureIoTClient 24:2c59c2d43ebf 522
AzureIoTClient 28:add19eb7defa 523 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 524 }
AzureIoTClient 4:98007eb79fa8 525 else
AzureIoTClient 4:98007eb79fa8 526 {
AzureIoTClient 43:4c1e4e94cdd3 527 /* Codes_S_R_S_CONNECTION_01_219: [The error description shall be set to an implementation defined string.] */
AzureIoTClient 28:add19eb7defa 528 if (error_set_description(error_handle, description) != 0)
AzureIoTClient 28:add19eb7defa 529 {
AzureIoTClient 28:add19eb7defa 530 LogError("Cannot set error description on CLOSE frame");
AzureIoTClient 24:2c59c2d43ebf 531
AzureIoTClient 43:4c1e4e94cdd3 532 /* Codes_S_R_S_CONNECTION_01_214: [If the close frame cannot be constructed or sent, the connection shall be closed and set to the END state.] */
AzureIoTClient 43:4c1e4e94cdd3 533 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 43:4c1e4e94cdd3 534 {
AzureIoTClient 43:4c1e4e94cdd3 535 LogError("xio_close failed");
AzureIoTClient 43:4c1e4e94cdd3 536 }
AzureIoTClient 43:4c1e4e94cdd3 537
AzureIoTClient 43:4c1e4e94cdd3 538 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 43:4c1e4e94cdd3 539 }
AzureIoTClient 43:4c1e4e94cdd3 540 else if ((info != NULL) &&
AzureIoTClient 43:4c1e4e94cdd3 541 (error_set_info(error_handle, info) != 0))
AzureIoTClient 43:4c1e4e94cdd3 542 {
AzureIoTClient 43:4c1e4e94cdd3 543 LogError("Cannot set error info on CLOSE frame");
AzureIoTClient 43:4c1e4e94cdd3 544
AzureIoTClient 43:4c1e4e94cdd3 545 /* Codes_S_R_S_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 546 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 547 {
AzureIoTClient 28:add19eb7defa 548 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 549 }
AzureIoTClient 24:2c59c2d43ebf 550
AzureIoTClient 28:add19eb7defa 551 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 28:add19eb7defa 552 }
AzureIoTClient 28:add19eb7defa 553 else if (send_close_frame(connection, error_handle) != 0)
AzureIoTClient 28:add19eb7defa 554 {
AzureIoTClient 28:add19eb7defa 555 LogError("Cannot send CLOSE frame");
AzureIoTClient 24:2c59c2d43ebf 556
AzureIoTClient 43:4c1e4e94cdd3 557 /* Codes_S_R_S_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 558 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 559 {
AzureIoTClient 28:add19eb7defa 560 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 561 }
AzureIoTClient 24:2c59c2d43ebf 562
AzureIoTClient 24:2c59c2d43ebf 563 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 564 }
AzureIoTClient 4:98007eb79fa8 565 else
AzureIoTClient 4:98007eb79fa8 566 {
AzureIoTClient 43:4c1e4e94cdd3 567 /* Codes_S_R_S_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 43:4c1e4e94cdd3 568 /* Codes_S_R_S_CONNECTION_01_055: [DISCARDING The DISCARDING state is a variant of the CLOSE SENT state where the close is triggered by an error.] */
AzureIoTClient 43:4c1e4e94cdd3 569 /* Codes_S_R_S_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 570 connection_set_state(connection, CONNECTION_STATE_DISCARDING);
AzureIoTClient 4:98007eb79fa8 571 }
Azure.IoT Build 0:6ae2f7bca550 572
AzureIoTClient 4:98007eb79fa8 573 error_destroy(error_handle);
AzureIoTClient 4:98007eb79fa8 574 }
Azure.IoT Build 0:6ae2f7bca550 575 }
Azure.IoT Build 0:6ae2f7bca550 576
AzureIoTClient 24:2c59c2d43ebf 577 static ENDPOINT_INSTANCE* find_session_endpoint_by_outgoing_channel(CONNECTION_HANDLE connection, uint16_t outgoing_channel)
Azure.IoT Build 0:6ae2f7bca550 578 {
AzureIoTClient 4:98007eb79fa8 579 uint32_t i;
AzureIoTClient 4:98007eb79fa8 580 ENDPOINT_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 581
AzureIoTClient 4:98007eb79fa8 582 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 583 {
AzureIoTClient 4:98007eb79fa8 584 if (connection->endpoints[i]->outgoing_channel == outgoing_channel)
AzureIoTClient 4:98007eb79fa8 585 {
AzureIoTClient 4:98007eb79fa8 586 break;
AzureIoTClient 4:98007eb79fa8 587 }
AzureIoTClient 4:98007eb79fa8 588 }
Azure.IoT Build 0:6ae2f7bca550 589
AzureIoTClient 4:98007eb79fa8 590 if (i == connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 591 {
AzureIoTClient 28:add19eb7defa 592 LogError("Cannot find session endpoint for channel %u", (unsigned int)outgoing_channel);
AzureIoTClient 28:add19eb7defa 593 result = NULL;
AzureIoTClient 4:98007eb79fa8 594 }
AzureIoTClient 4:98007eb79fa8 595 else
AzureIoTClient 4:98007eb79fa8 596 {
AzureIoTClient 4:98007eb79fa8 597 result = connection->endpoints[i];
AzureIoTClient 4:98007eb79fa8 598 }
Azure.IoT Build 0:6ae2f7bca550 599
AzureIoTClient 4:98007eb79fa8 600 return result;
Azure.IoT Build 0:6ae2f7bca550 601 }
Azure.IoT Build 0:6ae2f7bca550 602
AzureIoTClient 24:2c59c2d43ebf 603 static ENDPOINT_INSTANCE* find_session_endpoint_by_incoming_channel(CONNECTION_HANDLE connection, uint16_t incoming_channel)
Azure.IoT Build 0:6ae2f7bca550 604 {
AzureIoTClient 4:98007eb79fa8 605 uint32_t i;
AzureIoTClient 4:98007eb79fa8 606 ENDPOINT_INSTANCE* result;
Azure.IoT Build 0:6ae2f7bca550 607
AzureIoTClient 4:98007eb79fa8 608 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 609 {
AzureIoTClient 4:98007eb79fa8 610 if (connection->endpoints[i]->incoming_channel == incoming_channel)
AzureIoTClient 4:98007eb79fa8 611 {
AzureIoTClient 4:98007eb79fa8 612 break;
AzureIoTClient 4:98007eb79fa8 613 }
AzureIoTClient 4:98007eb79fa8 614 }
Azure.IoT Build 0:6ae2f7bca550 615
AzureIoTClient 4:98007eb79fa8 616 if (i == connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 617 {
AzureIoTClient 28:add19eb7defa 618 LogError("Cannot find session endpoint for channel %u", (unsigned int)incoming_channel);
AzureIoTClient 28:add19eb7defa 619 result = NULL;
AzureIoTClient 4:98007eb79fa8 620 }
AzureIoTClient 4:98007eb79fa8 621 else
AzureIoTClient 4:98007eb79fa8 622 {
AzureIoTClient 4:98007eb79fa8 623 result = connection->endpoints[i];
AzureIoTClient 4:98007eb79fa8 624 }
Azure.IoT Build 0:6ae2f7bca550 625
AzureIoTClient 4:98007eb79fa8 626 return result;
Azure.IoT Build 0:6ae2f7bca550 627 }
Azure.IoT Build 0:6ae2f7bca550 628
AzureIoTClient 24:2c59c2d43ebf 629 static int connection_byte_received(CONNECTION_HANDLE connection, unsigned char b)
Azure.IoT Build 0:6ae2f7bca550 630 {
AzureIoTClient 4:98007eb79fa8 631 int result;
Azure.IoT Build 0:6ae2f7bca550 632
AzureIoTClient 24:2c59c2d43ebf 633 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 634 {
AzureIoTClient 4:98007eb79fa8 635 default:
AzureIoTClient 28:add19eb7defa 636 LogError("Unknown connection state: %d", (int)connection->connection_state);
AzureIoTClient 28:add19eb7defa 637 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 638 break;
Azure.IoT Build 0:6ae2f7bca550 639
AzureIoTClient 43:4c1e4e94cdd3 640 /* Codes_S_R_S_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 641 case CONNECTION_STATE_START:
Azure.IoT Build 0:6ae2f7bca550 642
AzureIoTClient 43:4c1e4e94cdd3 643 /* Codes_S_R_S_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 644 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 24:2c59c2d43ebf 645 if (b != amqp_header[connection->header_bytes_received])
AzureIoTClient 4:98007eb79fa8 646 {
AzureIoTClient 43:4c1e4e94cdd3 647 /* Codes_S_R_S_CONNECTION_01_089: [If the incoming and outgoing protocol headers do not match, both peers MUST close their outgoing stream] */
AzureIoTClient 28:add19eb7defa 648 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 649 {
AzureIoTClient 28:add19eb7defa 650 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 651 }
AzureIoTClient 24:2c59c2d43ebf 652
AzureIoTClient 28:add19eb7defa 653 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 654 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 655 }
AzureIoTClient 4:98007eb79fa8 656 else
AzureIoTClient 4:98007eb79fa8 657 {
AzureIoTClient 28:add19eb7defa 658 connection->header_bytes_received++;
AzureIoTClient 24:2c59c2d43ebf 659 if (connection->header_bytes_received == sizeof(amqp_header))
AzureIoTClient 4:98007eb79fa8 660 {
AzureIoTClient 24:2c59c2d43ebf 661 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 662 {
AzureIoTClient 16:22a72cf8e416 663 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Header (AMQP 0.1.0.0)");
AzureIoTClient 4:98007eb79fa8 664 }
Azure.IoT Build 0:6ae2f7bca550 665
AzureIoTClient 24:2c59c2d43ebf 666 connection_set_state(connection, CONNECTION_STATE_HDR_EXCH);
Azure.IoT Build 0:6ae2f7bca550 667
AzureIoTClient 24:2c59c2d43ebf 668 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 669 {
AzureIoTClient 28:add19eb7defa 670 LogError("Cannot send open frame");
AzureIoTClient 28:add19eb7defa 671 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 672 }
AzureIoTClient 4:98007eb79fa8 673 }
Azure.IoT Build 0:6ae2f7bca550 674
AzureIoTClient 4:98007eb79fa8 675 result = 0;
AzureIoTClient 4:98007eb79fa8 676 }
AzureIoTClient 4:98007eb79fa8 677 break;
Azure.IoT Build 0:6ae2f7bca550 678
AzureIoTClient 43:4c1e4e94cdd3 679 /* Codes_S_R_S_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 680 case CONNECTION_STATE_HDR_RCVD:
Azure.IoT Build 0:6ae2f7bca550 681
AzureIoTClient 43:4c1e4e94cdd3 682 /* Codes_S_R_S_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 683 /* 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 684 case CONNECTION_STATE_HDR_EXCH:
Azure.IoT Build 0:6ae2f7bca550 685
AzureIoTClient 43:4c1e4e94cdd3 686 /* Codes_S_R_S_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 687 case CONNECTION_STATE_OPEN_RCVD:
Azure.IoT Build 0:6ae2f7bca550 688
AzureIoTClient 43:4c1e4e94cdd3 689 /* Codes_S_R_S_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 690 case CONNECTION_STATE_OPEN_SENT:
Azure.IoT Build 0:6ae2f7bca550 691
AzureIoTClient 43:4c1e4e94cdd3 692 /* Codes_S_R_S_CONNECTION_01_048: [OPENED In this state the connection header and the open frame have been both sent and received.] */
AzureIoTClient 4:98007eb79fa8 693 case CONNECTION_STATE_OPENED:
AzureIoTClient 43:4c1e4e94cdd3 694 /* Codes_S_R_S_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 695 if (frame_codec_receive_bytes(connection->frame_codec, &b, 1) != 0)
AzureIoTClient 4:98007eb79fa8 696 {
AzureIoTClient 28:add19eb7defa 697 LogError("Cannot process received bytes");
AzureIoTClient 43:4c1e4e94cdd3 698 /* Codes_S_R_S_CONNECTION_01_218: [The error amqp:internal-error shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 43:4c1e4e94cdd3 699 /* Codes_S_R_S_CONNECTION_01_219: [The error description shall be set to an implementation defined string.] */
AzureIoTClient 43:4c1e4e94cdd3 700 close_connection_with_error(connection, "amqp:internal-error", "connection_byte_received::frame_codec_receive_bytes failed", NULL);
AzureIoTClient 19:000ab4e6a2c1 701 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 702 }
AzureIoTClient 4:98007eb79fa8 703 else
AzureIoTClient 4:98007eb79fa8 704 {
AzureIoTClient 4:98007eb79fa8 705 result = 0;
AzureIoTClient 4:98007eb79fa8 706 }
Azure.IoT Build 0:6ae2f7bca550 707
AzureIoTClient 4:98007eb79fa8 708 break;
AzureIoTClient 4:98007eb79fa8 709 }
AzureIoTClient 4:98007eb79fa8 710
AzureIoTClient 4:98007eb79fa8 711 return result;
Azure.IoT Build 0:6ae2f7bca550 712 }
Azure.IoT Build 0:6ae2f7bca550 713
Azure.IoT Build 0:6ae2f7bca550 714 static void connection_on_bytes_received(void* context, const unsigned char* buffer, size_t size)
Azure.IoT Build 0:6ae2f7bca550 715 {
AzureIoTClient 4:98007eb79fa8 716 size_t i;
Azure.IoT Build 0:6ae2f7bca550 717
AzureIoTClient 4:98007eb79fa8 718 for (i = 0; i < size; i++)
AzureIoTClient 4:98007eb79fa8 719 {
AzureIoTClient 24:2c59c2d43ebf 720 if (connection_byte_received((CONNECTION_HANDLE)context, buffer[i]) != 0)
AzureIoTClient 4:98007eb79fa8 721 {
AzureIoTClient 28:add19eb7defa 722 LogError("Cannot process received bytes");
AzureIoTClient 28:add19eb7defa 723 break;
AzureIoTClient 4:98007eb79fa8 724 }
AzureIoTClient 4:98007eb79fa8 725 }
Azure.IoT Build 0:6ae2f7bca550 726 }
Azure.IoT Build 0:6ae2f7bca550 727
Azure.IoT Build 0:6ae2f7bca550 728 static void connection_on_io_open_complete(void* context, IO_OPEN_RESULT io_open_result)
Azure.IoT Build 0:6ae2f7bca550 729 {
AzureIoTClient 24:2c59c2d43ebf 730 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
Azure.IoT Build 0:6ae2f7bca550 731
AzureIoTClient 4:98007eb79fa8 732 if (io_open_result == IO_OPEN_OK)
AzureIoTClient 4:98007eb79fa8 733 {
AzureIoTClient 43:4c1e4e94cdd3 734 /* Codes_S_R_S_CONNECTION_01_084: [The connection_instance state machine implementing the protocol requirements shall be run as part of connection_dowork.] */
AzureIoTClient 24:2c59c2d43ebf 735 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 736 {
AzureIoTClient 4:98007eb79fa8 737 default:
AzureIoTClient 28:add19eb7defa 738 LogError("Unknown connection state: %d", (int)connection->connection_state);
AzureIoTClient 28:add19eb7defa 739 break;
Azure.IoT Build 0:6ae2f7bca550 740
AzureIoTClient 4:98007eb79fa8 741 case CONNECTION_STATE_START:
AzureIoTClient 43:4c1e4e94cdd3 742 /* Codes_S_R_S_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 43:4c1e4e94cdd3 743 /* Codes_S_R_S_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 744 if (send_header(connection) != 0)
AzureIoTClient 28:add19eb7defa 745 {
AzureIoTClient 28:add19eb7defa 746 LogError("Cannot send header");
AzureIoTClient 28:add19eb7defa 747 }
AzureIoTClient 4:98007eb79fa8 748 break;
Azure.IoT Build 0:6ae2f7bca550 749
AzureIoTClient 4:98007eb79fa8 750 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 4:98007eb79fa8 751 case CONNECTION_STATE_OPEN_SENT:
AzureIoTClient 4:98007eb79fa8 752 case CONNECTION_STATE_OPENED:
AzureIoTClient 4:98007eb79fa8 753 break;
Azure.IoT Build 0:6ae2f7bca550 754
AzureIoTClient 4:98007eb79fa8 755 case CONNECTION_STATE_HDR_EXCH:
AzureIoTClient 43:4c1e4e94cdd3 756 /* Codes_S_R_S_CONNECTION_01_002: [Each AMQP connection_instance begins with an exchange of capabilities and limitations, including the maximum frame size.] */
AzureIoTClient 43:4c1e4e94cdd3 757 /* Codes_S_R_S_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 43:4c1e4e94cdd3 758 /* Codes_S_R_S_CONNECTION_01_005: [The open frame describes the capabilities and limits of that peer.] */
AzureIoTClient 24:2c59c2d43ebf 759 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 760 {
AzureIoTClient 28:add19eb7defa 761 LogError("Cannot send OPEN frame");
AzureIoTClient 28:add19eb7defa 762 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 763 }
AzureIoTClient 4:98007eb79fa8 764 break;
Azure.IoT Build 0:6ae2f7bca550 765
AzureIoTClient 4:98007eb79fa8 766 case CONNECTION_STATE_OPEN_RCVD:
AzureIoTClient 4:98007eb79fa8 767 break;
AzureIoTClient 4:98007eb79fa8 768 }
AzureIoTClient 4:98007eb79fa8 769 }
AzureIoTClient 4:98007eb79fa8 770 else
AzureIoTClient 4:98007eb79fa8 771 {
AzureIoTClient 24:2c59c2d43ebf 772 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 773 }
Azure.IoT Build 0:6ae2f7bca550 774 }
Azure.IoT Build 0:6ae2f7bca550 775
Azure.IoT Build 0:6ae2f7bca550 776 static void connection_on_io_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 777 {
AzureIoTClient 28:add19eb7defa 778 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
Azure.IoT Build 0:6ae2f7bca550 779
AzureIoTClient 43:4c1e4e94cdd3 780 /* Codes_S_R_S_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 781 if (connection->on_io_error)
Azure.IoT Build 0:6ae2f7bca550 782 {
AzureIoTClient 28:add19eb7defa 783 connection->on_io_error(connection->on_io_error_callback_context);
Azure.IoT Build 0:6ae2f7bca550 784 }
Azure.IoT Build 0:6ae2f7bca550 785
AzureIoTClient 24:2c59c2d43ebf 786 if (connection->connection_state != CONNECTION_STATE_END)
AzureIoTClient 4:98007eb79fa8 787 {
AzureIoTClient 43:4c1e4e94cdd3 788 /* Codes_S_R_S_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 789 connection_set_state(connection, CONNECTION_STATE_ERROR);
AzureIoTClient 28:add19eb7defa 790 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 791 {
AzureIoTClient 28:add19eb7defa 792 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 793 }
AzureIoTClient 28:add19eb7defa 794 }
Azure.IoT Build 0:6ae2f7bca550 795 }
Azure.IoT Build 0:6ae2f7bca550 796
Azure.IoT Build 0:6ae2f7bca550 797 static void on_empty_amqp_frame_received(void* context, uint16_t channel)
Azure.IoT Build 0:6ae2f7bca550 798 {
AzureIoTClient 28:add19eb7defa 799 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 28:add19eb7defa 800 /* It does not matter on which channel we received the frame */
AzureIoTClient 28:add19eb7defa 801 (void)channel;
AzureIoTClient 24:2c59c2d43ebf 802
AzureIoTClient 28:add19eb7defa 803 if (connection->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 804 {
AzureIoTClient 16:22a72cf8e416 805 LOG(AZ_LOG_TRACE, LOG_LINE, "<- Empty frame");
AzureIoTClient 6:641a9672db08 806 }
AzureIoTClient 24:2c59c2d43ebf 807 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 4:98007eb79fa8 808 {
AzureIoTClient 28:add19eb7defa 809 LogError("Cannot get tickcounter value");
AzureIoTClient 28:add19eb7defa 810 }
Azure.IoT Build 0:6ae2f7bca550 811 }
Azure.IoT Build 0:6ae2f7bca550 812
Azure.IoT Build 0:6ae2f7bca550 813 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 814 {
AzureIoTClient 24:2c59c2d43ebf 815 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)context;
AzureIoTClient 24:2c59c2d43ebf 816
AzureIoTClient 28:add19eb7defa 817 (void)channel;
Azure.IoT Build 0:6ae2f7bca550 818
AzureIoTClient 24:2c59c2d43ebf 819 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 4:98007eb79fa8 820 {
AzureIoTClient 28:add19eb7defa 821 LogError("Cannot get tickcounter value");
AzureIoTClient 43:4c1e4e94cdd3 822 close_connection_with_error(connection, "amqp:internal-error", "cannot get current tick count", NULL);
AzureIoTClient 4:98007eb79fa8 823 }
AzureIoTClient 4:98007eb79fa8 824 else
AzureIoTClient 4:98007eb79fa8 825 {
AzureIoTClient 24:2c59c2d43ebf 826 if (connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 827 {
AzureIoTClient 24:2c59c2d43ebf 828 switch (connection->connection_state)
AzureIoTClient 4:98007eb79fa8 829 {
AzureIoTClient 4:98007eb79fa8 830 default:
AzureIoTClient 4:98007eb79fa8 831 if (performative == NULL)
AzureIoTClient 4:98007eb79fa8 832 {
AzureIoTClient 43:4c1e4e94cdd3 833 /* Codes_S_R_S_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 43:4c1e4e94cdd3 834 close_connection_with_error(connection, "amqp:internal-error", "connection_endpoint_frame_received::NULL performative", NULL);
AzureIoTClient 28:add19eb7defa 835 LogError("connection_endpoint_frame_received::NULL performative");
AzureIoTClient 28:add19eb7defa 836 }
AzureIoTClient 4:98007eb79fa8 837 else
AzureIoTClient 4:98007eb79fa8 838 {
AzureIoTClient 4:98007eb79fa8 839 AMQP_VALUE descriptor = amqpvalue_get_inplace_descriptor(performative);
Azure.IoT Build 0:6ae2f7bca550 840
AzureIoTClient 24:2c59c2d43ebf 841 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 842 {
Azure.IoT Build 5:ae49385aff34 843 log_incoming_frame(performative);
AzureIoTClient 4:98007eb79fa8 844 }
Azure.IoT Build 0:6ae2f7bca550 845
AzureIoTClient 4:98007eb79fa8 846 if (is_open_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 847 {
AzureIoTClient 4:98007eb79fa8 848 if (channel != 0)
AzureIoTClient 4:98007eb79fa8 849 {
AzureIoTClient 43:4c1e4e94cdd3 850 /* Codes_S_R_S_CONNECTION_01_006: [The open frame can only be sent on channel 0.] */
AzureIoTClient 43:4c1e4e94cdd3 851 /* Codes_S_R_S_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 43:4c1e4e94cdd3 852 close_connection_with_error(connection, "amqp:not-allowed", "OPEN frame received on a channel that is not 0", NULL);
AzureIoTClient 28:add19eb7defa 853 LogError("OPEN frame received on a channel that is not 0");
AzureIoTClient 28:add19eb7defa 854 }
Azure.IoT Build 0:6ae2f7bca550 855
AzureIoTClient 24:2c59c2d43ebf 856 if (connection->connection_state == CONNECTION_STATE_OPENED)
AzureIoTClient 4:98007eb79fa8 857 {
AzureIoTClient 43:4c1e4e94cdd3 858 /* Codes_S_R_S_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 43:4c1e4e94cdd3 859 close_connection_with_error(connection, "amqp:illegal-state", "OPEN frame received in the OPENED state", NULL);
AzureIoTClient 28:add19eb7defa 860 LogError("OPEN frame received in the OPENED state");
AzureIoTClient 28:add19eb7defa 861 }
AzureIoTClient 24:2c59c2d43ebf 862 else if ((connection->connection_state == CONNECTION_STATE_OPEN_SENT) ||
AzureIoTClient 24:2c59c2d43ebf 863 (connection->connection_state == CONNECTION_STATE_HDR_EXCH))
AzureIoTClient 4:98007eb79fa8 864 {
AzureIoTClient 4:98007eb79fa8 865 OPEN_HANDLE open_handle;
AzureIoTClient 4:98007eb79fa8 866 if (amqpvalue_get_open(performative, &open_handle) != 0)
AzureIoTClient 4:98007eb79fa8 867 {
AzureIoTClient 43:4c1e4e94cdd3 868 /* Codes_S_R_S_CONNECTION_01_143: [If any of the values in the received open frame are invalid then the connection shall be closed.] */
AzureIoTClient 43:4c1e4e94cdd3 869 /* Codes_S_R_S_CONNECTION_01_220: [The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 43:4c1e4e94cdd3 870 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing OPEN frame", NULL);
AzureIoTClient 28:add19eb7defa 871 LogError("connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 872 }
AzureIoTClient 4:98007eb79fa8 873 else
AzureIoTClient 4:98007eb79fa8 874 {
AzureIoTClient 35:d0bed2404ee9 875 if (open_get_idle_time_out(open_handle, &connection->remote_idle_timeout) == 0)
AzureIoTClient 35:d0bed2404ee9 876 {
AzureIoTClient 35:d0bed2404ee9 877 /* since we obtained the remote_idle_timeout, compute at what millisecond we should send the empty frame */
AzureIoTClient 35:d0bed2404ee9 878 connection->remote_idle_timeout_send_frame_millisecond = (milliseconds)(connection->idle_timeout_empty_frame_send_ratio * connection->remote_idle_timeout);
AzureIoTClient 35:d0bed2404ee9 879 }
AzureIoTClient 35:d0bed2404ee9 880
AzureIoTClient 24:2c59c2d43ebf 881 if ((open_get_max_frame_size(open_handle, &connection->remote_max_frame_size) != 0) ||
AzureIoTClient 43:4c1e4e94cdd3 882 /* Codes_S_R_S_CONNECTION_01_167: [Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.] */
AzureIoTClient 24:2c59c2d43ebf 883 (connection->remote_max_frame_size < 512))
AzureIoTClient 4:98007eb79fa8 884 {
AzureIoTClient 43:4c1e4e94cdd3 885 /* Codes_S_R_S_CONNECTION_01_143: [If any of the values in the received open frame are invalid then the connection shall be closed.] */
AzureIoTClient 43:4c1e4e94cdd3 886 /* Codes_S_R_S_CONNECTION_01_220: [The error amqp:invalid-field shall be set in the error.condition field of the CLOSE frame.] */
AzureIoTClient 43:4c1e4e94cdd3 887 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing OPEN frame", NULL);
AzureIoTClient 28:add19eb7defa 888 LogError("connection_endpoint_frame_received::failed parsing OPEN frame");
AzureIoTClient 28:add19eb7defa 889 }
AzureIoTClient 4:98007eb79fa8 890 else
AzureIoTClient 4:98007eb79fa8 891 {
AzureIoTClient 24:2c59c2d43ebf 892 if (connection->connection_state == CONNECTION_STATE_OPEN_SENT)
AzureIoTClient 4:98007eb79fa8 893 {
AzureIoTClient 24:2c59c2d43ebf 894 connection_set_state(connection, CONNECTION_STATE_OPENED);
AzureIoTClient 4:98007eb79fa8 895 }
AzureIoTClient 4:98007eb79fa8 896 else
AzureIoTClient 4:98007eb79fa8 897 {
AzureIoTClient 24:2c59c2d43ebf 898 if (send_open_frame(connection) != 0)
AzureIoTClient 4:98007eb79fa8 899 {
AzureIoTClient 24:2c59c2d43ebf 900 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 901 }
AzureIoTClient 4:98007eb79fa8 902 else
AzureIoTClient 4:98007eb79fa8 903 {
AzureIoTClient 24:2c59c2d43ebf 904 connection_set_state(connection, CONNECTION_STATE_OPENED);
AzureIoTClient 4:98007eb79fa8 905 }
AzureIoTClient 4:98007eb79fa8 906 }
AzureIoTClient 4:98007eb79fa8 907 }
Azure.IoT Build 0:6ae2f7bca550 908
AzureIoTClient 4:98007eb79fa8 909 open_destroy(open_handle);
AzureIoTClient 4:98007eb79fa8 910 }
AzureIoTClient 4:98007eb79fa8 911 }
AzureIoTClient 4:98007eb79fa8 912 else
AzureIoTClient 4:98007eb79fa8 913 {
AzureIoTClient 4:98007eb79fa8 914 /* do nothing for now ... */
AzureIoTClient 4:98007eb79fa8 915 }
AzureIoTClient 4:98007eb79fa8 916 }
AzureIoTClient 4:98007eb79fa8 917 else if (is_close_type_by_descriptor(descriptor))
AzureIoTClient 4:98007eb79fa8 918 {
AzureIoTClient 43:4c1e4e94cdd3 919 /* Codes_S_R_S_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 920
AzureIoTClient 43:4c1e4e94cdd3 921 /* Codes_S_R_S_CONNECTION_01_225: [HDR_RCVD HDR OPEN] */
AzureIoTClient 24:2c59c2d43ebf 922 if ((connection->connection_state == CONNECTION_STATE_HDR_RCVD) ||
AzureIoTClient 43:4c1e4e94cdd3 923 /* Codes_S_R_S_CONNECTION_01_227: [HDR_EXCH OPEN OPEN] */
AzureIoTClient 24:2c59c2d43ebf 924 (connection->connection_state == CONNECTION_STATE_HDR_EXCH) ||
AzureIoTClient 43:4c1e4e94cdd3 925 /* Codes_S_R_S_CONNECTION_01_228: [OPEN_RCVD OPEN *] */
AzureIoTClient 24:2c59c2d43ebf 926 (connection->connection_state == CONNECTION_STATE_OPEN_RCVD) ||
AzureIoTClient 43:4c1e4e94cdd3 927 /* Codes_S_R_S_CONNECTION_01_235: [CLOSE_SENT - * TCP Close for Write] */
AzureIoTClient 24:2c59c2d43ebf 928 (connection->connection_state == CONNECTION_STATE_CLOSE_SENT) ||
AzureIoTClient 43:4c1e4e94cdd3 929 /* Codes_S_R_S_CONNECTION_01_236: [DISCARDING - * TCP Close for Write] */
AzureIoTClient 24:2c59c2d43ebf 930 (connection->connection_state == CONNECTION_STATE_DISCARDING))
AzureIoTClient 4:98007eb79fa8 931 {
AzureIoTClient 28:add19eb7defa 932 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 933 {
AzureIoTClient 28:add19eb7defa 934 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 935 }
AzureIoTClient 28:add19eb7defa 936 }
AzureIoTClient 4:98007eb79fa8 937 else
AzureIoTClient 4:98007eb79fa8 938 {
AzureIoTClient 4:98007eb79fa8 939 CLOSE_HANDLE close_handle;
Azure.IoT Build 0:6ae2f7bca550 940
AzureIoTClient 43:4c1e4e94cdd3 941 /* Codes_S_R_S_CONNECTION_01_012: [A close frame MAY be received on any channel up to the maximum channel number negotiated in open.] */
AzureIoTClient 24:2c59c2d43ebf 942 if (channel > connection->channel_max)
AzureIoTClient 4:98007eb79fa8 943 {
AzureIoTClient 43:4c1e4e94cdd3 944 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing CLOSE frame", NULL);
AzureIoTClient 28:add19eb7defa 945 LogError("connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 946 }
AzureIoTClient 4:98007eb79fa8 947 else
AzureIoTClient 4:98007eb79fa8 948 {
AzureIoTClient 4:98007eb79fa8 949 if (amqpvalue_get_close(performative, &close_handle) != 0)
AzureIoTClient 4:98007eb79fa8 950 {
AzureIoTClient 43:4c1e4e94cdd3 951 close_connection_with_error(connection, "amqp:invalid-field", "connection_endpoint_frame_received::failed parsing CLOSE frame", NULL);
AzureIoTClient 28:add19eb7defa 952 LogError("connection_endpoint_frame_received::failed parsing CLOSE frame");
AzureIoTClient 28:add19eb7defa 953 }
AzureIoTClient 4:98007eb79fa8 954 else
AzureIoTClient 4:98007eb79fa8 955 {
AzureIoTClient 43:4c1e4e94cdd3 956 ERROR_HANDLE error;
AzureIoTClient 43:4c1e4e94cdd3 957
AzureIoTClient 43:4c1e4e94cdd3 958 if (close_get_error(close_handle, &error) != 0)
AzureIoTClient 43:4c1e4e94cdd3 959 {
AzureIoTClient 43:4c1e4e94cdd3 960 error = NULL;
AzureIoTClient 43:4c1e4e94cdd3 961 }
AzureIoTClient 43:4c1e4e94cdd3 962
AzureIoTClient 4:98007eb79fa8 963 close_destroy(close_handle);
Azure.IoT Build 0:6ae2f7bca550 964
AzureIoTClient 24:2c59c2d43ebf 965 connection_set_state(connection, CONNECTION_STATE_CLOSE_RCVD);
Azure.IoT Build 0:6ae2f7bca550 966
AzureIoTClient 28:add19eb7defa 967 if (send_close_frame(connection, NULL) != 0)
AzureIoTClient 28:add19eb7defa 968 {
AzureIoTClient 28:add19eb7defa 969 LogError("Cannot send CLOSE frame");
AzureIoTClient 28:add19eb7defa 970 }
AzureIoTClient 24:2c59c2d43ebf 971
AzureIoTClient 43:4c1e4e94cdd3 972 /* Codes_S_R_S_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 973 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 974 {
AzureIoTClient 28:add19eb7defa 975 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 976 }
Azure.IoT Build 0:6ae2f7bca550 977
AzureIoTClient 24:2c59c2d43ebf 978 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 43:4c1e4e94cdd3 979
AzureIoTClient 43:4c1e4e94cdd3 980 if (connection->on_connection_close_received_event_subscription.on_connection_close_received != NULL)
AzureIoTClient 43:4c1e4e94cdd3 981 {
AzureIoTClient 43:4c1e4e94cdd3 982 connection->on_connection_close_received_event_subscription.on_connection_close_received(connection->on_connection_close_received_event_subscription.context, error);
AzureIoTClient 43:4c1e4e94cdd3 983 }
AzureIoTClient 43:4c1e4e94cdd3 984
AzureIoTClient 43:4c1e4e94cdd3 985 error_destroy(error);
AzureIoTClient 4:98007eb79fa8 986 }
AzureIoTClient 4:98007eb79fa8 987 }
AzureIoTClient 4:98007eb79fa8 988 }
AzureIoTClient 4:98007eb79fa8 989 }
AzureIoTClient 4:98007eb79fa8 990 else
AzureIoTClient 4:98007eb79fa8 991 {
AzureIoTClient 46:01f7ca900e07 992 uint64_t performative_ulong;
Azure.IoT Build 0:6ae2f7bca550 993
AzureIoTClient 46:01f7ca900e07 994 if (amqpvalue_get_ulong(descriptor, &performative_ulong) != 0)
AzureIoTClient 46:01f7ca900e07 995 {
AzureIoTClient 46:01f7ca900e07 996 LogError("Failed getting ulong amqp performative");
AzureIoTClient 46:01f7ca900e07 997 }
AzureIoTClient 46:01f7ca900e07 998 else
AzureIoTClient 4:98007eb79fa8 999 {
AzureIoTClient 46:01f7ca900e07 1000 switch (performative_ulong)
AzureIoTClient 46:01f7ca900e07 1001 {
AzureIoTClient 46:01f7ca900e07 1002 default:
AzureIoTClient 46:01f7ca900e07 1003 LogError("Bad performative: %02x", performative);
AzureIoTClient 46:01f7ca900e07 1004 break;
Azure.IoT Build 0:6ae2f7bca550 1005
AzureIoTClient 46:01f7ca900e07 1006 case AMQP_BEGIN:
AzureIoTClient 4:98007eb79fa8 1007 {
AzureIoTClient 46:01f7ca900e07 1008 BEGIN_HANDLE begin;
AzureIoTClient 46:01f7ca900e07 1009
AzureIoTClient 46:01f7ca900e07 1010 if (amqpvalue_get_begin(performative, &begin) != 0)
AzureIoTClient 46:01f7ca900e07 1011 {
AzureIoTClient 46:01f7ca900e07 1012 LogError("Cannot get begin performative");
AzureIoTClient 46:01f7ca900e07 1013 }
AzureIoTClient 46:01f7ca900e07 1014 else
AzureIoTClient 46:01f7ca900e07 1015 {
AzureIoTClient 46:01f7ca900e07 1016 uint16_t remote_channel;
AzureIoTClient 46:01f7ca900e07 1017 ENDPOINT_HANDLE new_endpoint = NULL;
AzureIoTClient 46:01f7ca900e07 1018 bool remote_begin = false;
Azure.IoT Build 0:6ae2f7bca550 1019
AzureIoTClient 46:01f7ca900e07 1020 if (begin_get_remote_channel(begin, &remote_channel) != 0)
AzureIoTClient 4:98007eb79fa8 1021 {
AzureIoTClient 46:01f7ca900e07 1022 remote_begin = true;
AzureIoTClient 46:01f7ca900e07 1023 if (connection->on_new_endpoint != NULL)
AzureIoTClient 4:98007eb79fa8 1024 {
AzureIoTClient 46:01f7ca900e07 1025 new_endpoint = connection_create_endpoint(connection);
AzureIoTClient 46:01f7ca900e07 1026 if (!connection->on_new_endpoint(connection->on_new_endpoint_callback_context, new_endpoint))
AzureIoTClient 46:01f7ca900e07 1027 {
AzureIoTClient 46:01f7ca900e07 1028 connection_destroy_endpoint(new_endpoint);
AzureIoTClient 46:01f7ca900e07 1029 new_endpoint = NULL;
AzureIoTClient 46:01f7ca900e07 1030 }
AzureIoTClient 4:98007eb79fa8 1031 }
AzureIoTClient 4:98007eb79fa8 1032 }
Azure.IoT Build 0:6ae2f7bca550 1033
AzureIoTClient 46:01f7ca900e07 1034 if (!remote_begin)
AzureIoTClient 4:98007eb79fa8 1035 {
AzureIoTClient 46:01f7ca900e07 1036 ENDPOINT_INSTANCE* session_endpoint = find_session_endpoint_by_outgoing_channel(connection, remote_channel);
AzureIoTClient 46:01f7ca900e07 1037 if (session_endpoint == NULL)
AzureIoTClient 46:01f7ca900e07 1038 {
AzureIoTClient 46:01f7ca900e07 1039 LogError("Cannot create session endpoint");
AzureIoTClient 46:01f7ca900e07 1040 }
AzureIoTClient 46:01f7ca900e07 1041 else
AzureIoTClient 46:01f7ca900e07 1042 {
AzureIoTClient 46:01f7ca900e07 1043 session_endpoint->incoming_channel = channel;
AzureIoTClient 46:01f7ca900e07 1044 session_endpoint->on_endpoint_frame_received(session_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 46:01f7ca900e07 1045 }
AzureIoTClient 28:add19eb7defa 1046 }
AzureIoTClient 4:98007eb79fa8 1047 else
AzureIoTClient 4:98007eb79fa8 1048 {
AzureIoTClient 46:01f7ca900e07 1049 if (new_endpoint != NULL)
AzureIoTClient 46:01f7ca900e07 1050 {
AzureIoTClient 46:01f7ca900e07 1051 new_endpoint->incoming_channel = channel;
AzureIoTClient 46:01f7ca900e07 1052 new_endpoint->on_endpoint_frame_received(new_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 46:01f7ca900e07 1053 }
AzureIoTClient 4:98007eb79fa8 1054 }
AzureIoTClient 46:01f7ca900e07 1055
AzureIoTClient 46:01f7ca900e07 1056 begin_destroy(begin);
AzureIoTClient 46:01f7ca900e07 1057 }
AzureIoTClient 46:01f7ca900e07 1058
AzureIoTClient 46:01f7ca900e07 1059 break;
AzureIoTClient 46:01f7ca900e07 1060 }
AzureIoTClient 46:01f7ca900e07 1061
AzureIoTClient 46:01f7ca900e07 1062 case AMQP_FLOW:
AzureIoTClient 46:01f7ca900e07 1063 case AMQP_TRANSFER:
AzureIoTClient 46:01f7ca900e07 1064 case AMQP_DISPOSITION:
AzureIoTClient 46:01f7ca900e07 1065 case AMQP_END:
AzureIoTClient 46:01f7ca900e07 1066 case AMQP_ATTACH:
AzureIoTClient 46:01f7ca900e07 1067 case AMQP_DETACH:
AzureIoTClient 46:01f7ca900e07 1068 {
AzureIoTClient 46:01f7ca900e07 1069 ENDPOINT_INSTANCE* session_endpoint = find_session_endpoint_by_incoming_channel(connection, channel);
AzureIoTClient 46:01f7ca900e07 1070 if (session_endpoint == NULL)
AzureIoTClient 46:01f7ca900e07 1071 {
AzureIoTClient 46:01f7ca900e07 1072 LogError("Cannot find session endpoint for channel %u", (unsigned int)channel);
AzureIoTClient 4:98007eb79fa8 1073 }
AzureIoTClient 4:98007eb79fa8 1074 else
AzureIoTClient 4:98007eb79fa8 1075 {
AzureIoTClient 46:01f7ca900e07 1076 session_endpoint->on_endpoint_frame_received(session_endpoint->callback_context, performative, payload_size, payload_bytes);
AzureIoTClient 4:98007eb79fa8 1077 }
Azure.IoT Build 0:6ae2f7bca550 1078
AzureIoTClient 46:01f7ca900e07 1079 break;
AzureIoTClient 4:98007eb79fa8 1080 }
AzureIoTClient 28:add19eb7defa 1081 }
AzureIoTClient 4:98007eb79fa8 1082 }
AzureIoTClient 4:98007eb79fa8 1083 }
AzureIoTClient 4:98007eb79fa8 1084 }
AzureIoTClient 4:98007eb79fa8 1085 break;
Azure.IoT Build 0:6ae2f7bca550 1086
AzureIoTClient 4:98007eb79fa8 1087 case CONNECTION_STATE_START:
AzureIoTClient 43:4c1e4e94cdd3 1088 /* Codes_S_R_S_CONNECTION_01_224: [START HDR HDR] */
AzureIoTClient 4:98007eb79fa8 1089 case CONNECTION_STATE_HDR_SENT:
AzureIoTClient 43:4c1e4e94cdd3 1090 /* Codes_S_R_S_CONNECTION_01_226: [HDR_SENT OPEN HDR] */
AzureIoTClient 4:98007eb79fa8 1091 case CONNECTION_STATE_OPEN_PIPE:
AzureIoTClient 43:4c1e4e94cdd3 1092 /* Codes_S_R_S_CONNECTION_01_230: [OPEN_PIPE ** HDR] */
AzureIoTClient 4:98007eb79fa8 1093 case CONNECTION_STATE_OC_PIPE:
AzureIoTClient 43:4c1e4e94cdd3 1094 /* Codes_S_R_S_CONNECTION_01_232: [OC_PIPE - HDR TCP Close for Write] */
AzureIoTClient 4:98007eb79fa8 1095 case CONNECTION_STATE_CLOSE_RCVD:
AzureIoTClient 43:4c1e4e94cdd3 1096 /* Codes_S_R_S_CONNECTION_01_234: [CLOSE_RCVD * - TCP Close for Read] */
AzureIoTClient 4:98007eb79fa8 1097 case CONNECTION_STATE_END:
AzureIoTClient 43:4c1e4e94cdd3 1098 /* Codes_S_R_S_CONNECTION_01_237: [END - - TCP Close] */
AzureIoTClient 28:add19eb7defa 1099 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1100 {
AzureIoTClient 28:add19eb7defa 1101 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 1102 }
AzureIoTClient 28:add19eb7defa 1103 break;
AzureIoTClient 4:98007eb79fa8 1104 }
AzureIoTClient 4:98007eb79fa8 1105 }
AzureIoTClient 4:98007eb79fa8 1106 }
Azure.IoT Build 0:6ae2f7bca550 1107 }
Azure.IoT Build 0:6ae2f7bca550 1108
Azure.IoT Build 0:6ae2f7bca550 1109 static void frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 1110 {
AzureIoTClient 43:4c1e4e94cdd3 1111 /* Bug: some error handling should happen here
AzureIoTClient 6:641a9672db08 1112 Filed: uAMQP: frame_codec error and amqp_frame_codec_error should handle the errors */
AzureIoTClient 28:add19eb7defa 1113 LogError("A frame_codec_error occured");
AzureIoTClient 28:add19eb7defa 1114 (void)context;
Azure.IoT Build 0:6ae2f7bca550 1115 }
Azure.IoT Build 0:6ae2f7bca550 1116
Azure.IoT Build 0:6ae2f7bca550 1117 static void amqp_frame_codec_error(void* context)
Azure.IoT Build 0:6ae2f7bca550 1118 {
AzureIoTClient 6:641a9672db08 1119 /* Bug: some error handling should happen here
AzureIoTClient 6:641a9672db08 1120 Filed: uAMQP: frame_codec error and amqp_frame_codec_error should handle the errors */
AzureIoTClient 28:add19eb7defa 1121 LogError("An amqp_frame_codec_error occured");
AzureIoTClient 28:add19eb7defa 1122 (void)context;
Azure.IoT Build 0:6ae2f7bca550 1123 }
Azure.IoT Build 0:6ae2f7bca550 1124
AzureIoTClient 43:4c1e4e94cdd3 1125 /* Codes_S_R_S_CONNECTION_01_001: [connection_create shall open a new connection to a specified host/port.] */
Azure.IoT Build 0:6ae2f7bca550 1126 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 1127 {
Azure.IoT Build 5:ae49385aff34 1128 return connection_create2(xio, hostname, container_id, on_new_endpoint, callback_context, NULL, NULL, NULL, NULL);
Azure.IoT Build 0:6ae2f7bca550 1129 }
Azure.IoT Build 0:6ae2f7bca550 1130
AzureIoTClient 43:4c1e4e94cdd3 1131 /* Codes_S_R_S_CONNECTION_01_001: [connection_create shall open a new connection to a specified host/port.] */
AzureIoTClient 43:4c1e4e94cdd3 1132 /* Codes_S_R_S_CONNECTION_22_002: [connection_create shall allow registering connections state and io error callbacks.] */
Azure.IoT Build 5:ae49385aff34 1133 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 1134 {
AzureIoTClient 35:d0bed2404ee9 1135 CONNECTION_HANDLE connection;
Azure.IoT Build 0:6ae2f7bca550 1136
AzureIoTClient 4:98007eb79fa8 1137 if ((xio == NULL) ||
AzureIoTClient 4:98007eb79fa8 1138 (container_id == NULL))
AzureIoTClient 4:98007eb79fa8 1139 {
AzureIoTClient 43:4c1e4e94cdd3 1140 /* Codes_S_R_S_CONNECTION_01_071: [If xio or container_id is NULL, connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1141 LogError("Bad arguments: xio = %p, container_id = %p",
AzureIoTClient 28:add19eb7defa 1142 xio, container_id);
AzureIoTClient 35:d0bed2404ee9 1143 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1144 }
AzureIoTClient 4:98007eb79fa8 1145 else
AzureIoTClient 4:98007eb79fa8 1146 {
AzureIoTClient 35:d0bed2404ee9 1147 connection = (CONNECTION_HANDLE)malloc(sizeof(CONNECTION_INSTANCE));
AzureIoTClient 43:4c1e4e94cdd3 1148 /* Codes_S_R_S_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 35:d0bed2404ee9 1149 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1150 {
AzureIoTClient 28:add19eb7defa 1151 LogError("Cannot allocate memory for connection");
AzureIoTClient 28:add19eb7defa 1152 }
AzureIoTClient 28:add19eb7defa 1153 else
AzureIoTClient 28:add19eb7defa 1154 {
AzureIoTClient 35:d0bed2404ee9 1155 connection->io = xio;
Azure.IoT Build 0:6ae2f7bca550 1156
AzureIoTClient 43:4c1e4e94cdd3 1157 /* Codes_S_R_S_CONNECTION_01_082: [connection_create shall allocate a new frame_codec instance to be used for frame encoding/decoding.] */
AzureIoTClient 35:d0bed2404ee9 1158 connection->frame_codec = frame_codec_create(frame_codec_error, connection);
AzureIoTClient 35:d0bed2404ee9 1159 if (connection->frame_codec == NULL)
AzureIoTClient 4:98007eb79fa8 1160 {
AzureIoTClient 43:4c1e4e94cdd3 1161 /* Codes_S_R_S_CONNECTION_01_083: [If frame_codec_create fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1162 LogError("Cannot create frame_codec");
AzureIoTClient 35:d0bed2404ee9 1163 free(connection);
AzureIoTClient 35:d0bed2404ee9 1164 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1165 }
AzureIoTClient 4:98007eb79fa8 1166 else
AzureIoTClient 4:98007eb79fa8 1167 {
AzureIoTClient 35:d0bed2404ee9 1168 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 1169 if (connection->amqp_frame_codec == NULL)
AzureIoTClient 4:98007eb79fa8 1170 {
AzureIoTClient 43:4c1e4e94cdd3 1171 /* Codes_S_R_S_CONNECTION_01_108: [If amqp_frame_codec_create fails, connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1172 LogError("Cannot create amqp_frame_codec");
AzureIoTClient 35:d0bed2404ee9 1173 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1174 free(connection);
AzureIoTClient 35:d0bed2404ee9 1175 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1176 }
AzureIoTClient 4:98007eb79fa8 1177 else
AzureIoTClient 4:98007eb79fa8 1178 {
AzureIoTClient 4:98007eb79fa8 1179 if (hostname != NULL)
AzureIoTClient 4:98007eb79fa8 1180 {
AzureIoTClient 23:1111ee8bcba4 1181 size_t hostname_length = strlen(hostname);
AzureIoTClient 35:d0bed2404ee9 1182 connection->host_name = (char*)malloc(hostname_length + 1);
AzureIoTClient 35:d0bed2404ee9 1183 if (connection->host_name == NULL)
AzureIoTClient 4:98007eb79fa8 1184 {
AzureIoTClient 43:4c1e4e94cdd3 1185 /* Codes_S_R_S_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1186 LogError("Cannot allocate memory for host name");
AzureIoTClient 35:d0bed2404ee9 1187 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1188 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1189 free(connection);
AzureIoTClient 35:d0bed2404ee9 1190 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1191 }
AzureIoTClient 4:98007eb79fa8 1192 else
AzureIoTClient 4:98007eb79fa8 1193 {
AzureIoTClient 35:d0bed2404ee9 1194 (void)memcpy(connection->host_name, hostname, hostname_length + 1);
AzureIoTClient 4:98007eb79fa8 1195 }
AzureIoTClient 4:98007eb79fa8 1196 }
AzureIoTClient 4:98007eb79fa8 1197 else
AzureIoTClient 4:98007eb79fa8 1198 {
AzureIoTClient 35:d0bed2404ee9 1199 connection->host_name = NULL;
AzureIoTClient 4:98007eb79fa8 1200 }
Azure.IoT Build 0:6ae2f7bca550 1201
AzureIoTClient 35:d0bed2404ee9 1202 if (connection != NULL)
AzureIoTClient 4:98007eb79fa8 1203 {
AzureIoTClient 23:1111ee8bcba4 1204 size_t container_id_length = strlen(container_id);
AzureIoTClient 35:d0bed2404ee9 1205 connection->container_id = (char*)malloc(container_id_length + 1);
AzureIoTClient 35:d0bed2404ee9 1206 if (connection->container_id == NULL)
AzureIoTClient 4:98007eb79fa8 1207 {
AzureIoTClient 43:4c1e4e94cdd3 1208 /* Codes_S_R_S_CONNECTION_01_081: [If allocating the memory for the connection fails then connection_create shall return NULL.] */
AzureIoTClient 28:add19eb7defa 1209 LogError("Cannot allocate memory for container_id");
AzureIoTClient 35:d0bed2404ee9 1210 free(connection->host_name);
AzureIoTClient 35:d0bed2404ee9 1211 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1212 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1213 free(connection);
AzureIoTClient 35:d0bed2404ee9 1214 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1215 }
AzureIoTClient 4:98007eb79fa8 1216 else
AzureIoTClient 4:98007eb79fa8 1217 {
AzureIoTClient 35:d0bed2404ee9 1218 connection->tick_counter = tickcounter_create();
AzureIoTClient 35:d0bed2404ee9 1219 if (connection->tick_counter == NULL)
AzureIoTClient 4:98007eb79fa8 1220 {
AzureIoTClient 28:add19eb7defa 1221 LogError("Cannot create tick counter");
AzureIoTClient 35:d0bed2404ee9 1222 free(connection->container_id);
AzureIoTClient 35:d0bed2404ee9 1223 free(connection->host_name);
AzureIoTClient 35:d0bed2404ee9 1224 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1225 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1226 free(connection);
AzureIoTClient 35:d0bed2404ee9 1227 connection = NULL;
AzureIoTClient 4:98007eb79fa8 1228 }
AzureIoTClient 4:98007eb79fa8 1229 else
AzureIoTClient 4:98007eb79fa8 1230 {
AzureIoTClient 35:d0bed2404ee9 1231 (void)memcpy(connection->container_id, container_id, container_id_length + 1);
Azure.IoT Build 0:6ae2f7bca550 1232
AzureIoTClient 43:4c1e4e94cdd3 1233 /* Codes_S_R_S_CONNECTION_01_173: [<field name="max-frame-size" type="uint" default="4294967295"/>] */
AzureIoTClient 35:d0bed2404ee9 1234 connection->max_frame_size = 4294967295u;
AzureIoTClient 4:98007eb79fa8 1235 /* Codes: [<field name="channel-max" type="ushort" default="65535"/>] */
AzureIoTClient 35:d0bed2404ee9 1236 connection->channel_max = 65535;
Azure.IoT Build 0:6ae2f7bca550 1237
AzureIoTClient 43:4c1e4e94cdd3 1238 /* Codes_S_R_S_CONNECTION_01_175: [<field name="idle-time-out" type="milliseconds"/>] */
AzureIoTClient 43:4c1e4e94cdd3 1239 /* Codes_S_R_S_CONNECTION_01_192: [A value of zero is the same as if it was not set (null).] */
AzureIoTClient 35:d0bed2404ee9 1240 connection->idle_timeout = 0;
AzureIoTClient 35:d0bed2404ee9 1241 connection->remote_idle_timeout = 0;
AzureIoTClient 35:d0bed2404ee9 1242 connection->remote_idle_timeout_send_frame_millisecond = 0;
AzureIoTClient 35:d0bed2404ee9 1243 connection->idle_timeout_empty_frame_send_ratio = 0.5;
Azure.IoT Build 0:6ae2f7bca550 1244
AzureIoTClient 35:d0bed2404ee9 1245 connection->endpoint_count = 0;
AzureIoTClient 35:d0bed2404ee9 1246 connection->endpoints = NULL;
AzureIoTClient 35:d0bed2404ee9 1247 connection->header_bytes_received = 0;
AzureIoTClient 35:d0bed2404ee9 1248 connection->is_remote_frame_received = 0;
AzureIoTClient 41:0e723f9cbd89 1249 connection->properties = NULL;
Azure.IoT Build 0:6ae2f7bca550 1250
AzureIoTClient 35:d0bed2404ee9 1251 connection->is_underlying_io_open = 0;
AzureIoTClient 35:d0bed2404ee9 1252 connection->remote_max_frame_size = 512;
AzureIoTClient 35:d0bed2404ee9 1253 connection->is_trace_on = 0;
Azure.IoT Build 0:6ae2f7bca550 1254
AzureIoTClient 4:98007eb79fa8 1255 /* Mark that settings have not yet been set by the user */
AzureIoTClient 35:d0bed2404ee9 1256 connection->idle_timeout_specified = 0;
Azure.IoT Build 0:6ae2f7bca550 1257
AzureIoTClient 35:d0bed2404ee9 1258 connection->on_new_endpoint = on_new_endpoint;
AzureIoTClient 35:d0bed2404ee9 1259 connection->on_new_endpoint_callback_context = callback_context;
Azure.IoT Build 0:6ae2f7bca550 1260
AzureIoTClient 43:4c1e4e94cdd3 1261 connection->on_connection_close_received_event_subscription.on_connection_close_received = NULL;
AzureIoTClient 43:4c1e4e94cdd3 1262 connection->on_connection_close_received_event_subscription.context = NULL;
AzureIoTClient 43:4c1e4e94cdd3 1263
AzureIoTClient 35:d0bed2404ee9 1264 connection->on_io_error = on_io_error;
AzureIoTClient 35:d0bed2404ee9 1265 connection->on_io_error_callback_context = on_io_error_context;
AzureIoTClient 35:d0bed2404ee9 1266 connection->on_connection_state_changed = on_connection_state_changed;
AzureIoTClient 35:d0bed2404ee9 1267 connection->on_connection_state_changed_callback_context = on_connection_state_changed_context;
Azure.IoT Build 0:6ae2f7bca550 1268
AzureIoTClient 35:d0bed2404ee9 1269 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_received_time) != 0)
AzureIoTClient 20:206846c14c80 1270 {
AzureIoTClient 20:206846c14c80 1271 LogError("Could not retrieve time for last frame received time");
AzureIoTClient 35:d0bed2404ee9 1272 tickcounter_destroy(connection->tick_counter);
AzureIoTClient 35:d0bed2404ee9 1273 free(connection->container_id);
AzureIoTClient 35:d0bed2404ee9 1274 free(connection->host_name);
AzureIoTClient 35:d0bed2404ee9 1275 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 35:d0bed2404ee9 1276 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 35:d0bed2404ee9 1277 free(connection);
AzureIoTClient 35:d0bed2404ee9 1278 connection = NULL;
AzureIoTClient 20:206846c14c80 1279 }
AzureIoTClient 20:206846c14c80 1280 else
AzureIoTClient 20:206846c14c80 1281 {
AzureIoTClient 35:d0bed2404ee9 1282 connection->last_frame_sent_time = connection->last_frame_received_time;
AzureIoTClient 20:206846c14c80 1283
AzureIoTClient 43:4c1e4e94cdd3 1284 /* Codes_S_R_S_CONNECTION_01_072: [When connection_create succeeds, the state of the connection shall be CONNECTION_STATE_START.] */
AzureIoTClient 35:d0bed2404ee9 1285 connection_set_state(connection, CONNECTION_STATE_START);
AzureIoTClient 20:206846c14c80 1286 }
AzureIoTClient 4:98007eb79fa8 1287 }
AzureIoTClient 4:98007eb79fa8 1288 }
AzureIoTClient 4:98007eb79fa8 1289 }
AzureIoTClient 4:98007eb79fa8 1290 }
AzureIoTClient 4:98007eb79fa8 1291 }
AzureIoTClient 4:98007eb79fa8 1292 }
AzureIoTClient 4:98007eb79fa8 1293 }
Azure.IoT Build 0:6ae2f7bca550 1294
AzureIoTClient 35:d0bed2404ee9 1295 return connection;
Azure.IoT Build 0:6ae2f7bca550 1296 }
Azure.IoT Build 0:6ae2f7bca550 1297
Azure.IoT Build 0:6ae2f7bca550 1298 void connection_destroy(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1299 {
AzureIoTClient 43:4c1e4e94cdd3 1300 /* Codes_S_R_S_CONNECTION_01_079: [If handle is NULL, connection_destroy shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1301 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1302 {
AzureIoTClient 28:add19eb7defa 1303 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1304 }
AzureIoTClient 28:add19eb7defa 1305 else
AzureIoTClient 28:add19eb7defa 1306 {
AzureIoTClient 43:4c1e4e94cdd3 1307 /* Codes_S_R_S_CONNECTION_01_073: [connection_destroy shall free all resources associated with a connection.] */
AzureIoTClient 4:98007eb79fa8 1308 if (connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1309 {
AzureIoTClient 43:4c1e4e94cdd3 1310 (void)connection_close(connection, NULL, NULL, NULL);
AzureIoTClient 4:98007eb79fa8 1311 }
Azure.IoT Build 0:6ae2f7bca550 1312
AzureIoTClient 4:98007eb79fa8 1313 amqp_frame_codec_destroy(connection->amqp_frame_codec);
AzureIoTClient 4:98007eb79fa8 1314 frame_codec_destroy(connection->frame_codec);
AzureIoTClient 4:98007eb79fa8 1315 tickcounter_destroy(connection->tick_counter);
AzureIoTClient 41:0e723f9cbd89 1316 if (connection->properties != NULL)
AzureIoTClient 41:0e723f9cbd89 1317 {
AzureIoTClient 41:0e723f9cbd89 1318 amqpvalue_destroy(connection->properties);
AzureIoTClient 41:0e723f9cbd89 1319 }
Azure.IoT Build 0:6ae2f7bca550 1320
AzureIoTClient 21:f9c433d8e6ca 1321 free(connection->host_name);
AzureIoTClient 21:f9c433d8e6ca 1322 free(connection->container_id);
Azure.IoT Build 0:6ae2f7bca550 1323
AzureIoTClient 43:4c1e4e94cdd3 1324 /* Codes_S_R_S_CONNECTION_01_074: [connection_destroy shall close the socket connection.] */
AzureIoTClient 21:f9c433d8e6ca 1325 free(connection);
AzureIoTClient 4:98007eb79fa8 1326 }
Azure.IoT Build 0:6ae2f7bca550 1327 }
Azure.IoT Build 0:6ae2f7bca550 1328
Azure.IoT Build 0:6ae2f7bca550 1329 int connection_open(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1330 {
AzureIoTClient 4:98007eb79fa8 1331 int result;
Azure.IoT Build 0:6ae2f7bca550 1332
AzureIoTClient 4:98007eb79fa8 1333 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1334 {
AzureIoTClient 28:add19eb7defa 1335 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1336 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1337 }
AzureIoTClient 4:98007eb79fa8 1338 else
AzureIoTClient 4:98007eb79fa8 1339 {
AzureIoTClient 4:98007eb79fa8 1340 if (!connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1341 {
AzureIoTClient 4:98007eb79fa8 1342 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 1343 {
AzureIoTClient 28:add19eb7defa 1344 LogError("Opening the underlying IO failed");
AzureIoTClient 28:add19eb7defa 1345 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 1346 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1347 }
AzureIoTClient 4:98007eb79fa8 1348 else
AzureIoTClient 4:98007eb79fa8 1349 {
AzureIoTClient 4:98007eb79fa8 1350 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1351
AzureIoTClient 4:98007eb79fa8 1352 connection_set_state(connection, CONNECTION_STATE_START);
Azure.IoT Build 0:6ae2f7bca550 1353
AzureIoTClient 4:98007eb79fa8 1354 result = 0;
AzureIoTClient 4:98007eb79fa8 1355 }
AzureIoTClient 4:98007eb79fa8 1356 }
AzureIoTClient 4:98007eb79fa8 1357 else
AzureIoTClient 4:98007eb79fa8 1358 {
AzureIoTClient 4:98007eb79fa8 1359 result = 0;
AzureIoTClient 4:98007eb79fa8 1360 }
AzureIoTClient 4:98007eb79fa8 1361 }
Azure.IoT Build 0:6ae2f7bca550 1362
AzureIoTClient 4:98007eb79fa8 1363 return result;
Azure.IoT Build 0:6ae2f7bca550 1364 }
Azure.IoT Build 0:6ae2f7bca550 1365
Azure.IoT Build 0:6ae2f7bca550 1366 int connection_listen(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1367 {
AzureIoTClient 4:98007eb79fa8 1368 int result;
Azure.IoT Build 0:6ae2f7bca550 1369
AzureIoTClient 4:98007eb79fa8 1370 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1371 {
AzureIoTClient 28:add19eb7defa 1372 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1373 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1374 }
AzureIoTClient 4:98007eb79fa8 1375 else
AzureIoTClient 4:98007eb79fa8 1376 {
AzureIoTClient 4:98007eb79fa8 1377 if (!connection->is_underlying_io_open)
AzureIoTClient 4:98007eb79fa8 1378 {
AzureIoTClient 4:98007eb79fa8 1379 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 1380 {
AzureIoTClient 28:add19eb7defa 1381 LogError("Opening the underlying IO failed");
AzureIoTClient 28:add19eb7defa 1382 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 19:000ab4e6a2c1 1383 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1384 }
AzureIoTClient 4:98007eb79fa8 1385 else
AzureIoTClient 4:98007eb79fa8 1386 {
AzureIoTClient 4:98007eb79fa8 1387 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1388
AzureIoTClient 4:98007eb79fa8 1389 connection_set_state(connection, CONNECTION_STATE_HDR_EXCH);
Azure.IoT Build 0:6ae2f7bca550 1390
AzureIoTClient 4:98007eb79fa8 1391 result = 0;
AzureIoTClient 4:98007eb79fa8 1392 }
AzureIoTClient 4:98007eb79fa8 1393 }
AzureIoTClient 4:98007eb79fa8 1394 else
AzureIoTClient 4:98007eb79fa8 1395 {
AzureIoTClient 4:98007eb79fa8 1396 result = 0;
AzureIoTClient 4:98007eb79fa8 1397 }
AzureIoTClient 4:98007eb79fa8 1398 }
Azure.IoT Build 0:6ae2f7bca550 1399
AzureIoTClient 4:98007eb79fa8 1400 return result;
Azure.IoT Build 0:6ae2f7bca550 1401 }
Azure.IoT Build 0:6ae2f7bca550 1402
AzureIoTClient 43:4c1e4e94cdd3 1403 int connection_close(CONNECTION_HANDLE connection, const char* condition_value, const char* description, AMQP_VALUE info)
Azure.IoT Build 0:6ae2f7bca550 1404 {
AzureIoTClient 4:98007eb79fa8 1405 int result;
Azure.IoT Build 0:6ae2f7bca550 1406
AzureIoTClient 4:98007eb79fa8 1407 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1408 {
AzureIoTClient 28:add19eb7defa 1409 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1410 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1411 }
AzureIoTClient 43:4c1e4e94cdd3 1412 else if ((info != NULL) &&
AzureIoTClient 43:4c1e4e94cdd3 1413 (amqpvalue_get_type(info) != AMQP_TYPE_MAP) &&
AzureIoTClient 43:4c1e4e94cdd3 1414 (amqpvalue_get_type(info) != AMQP_TYPE_NULL))
AzureIoTClient 43:4c1e4e94cdd3 1415 {
AzureIoTClient 43:4c1e4e94cdd3 1416 LogError("Invalid info, expected a map");
AzureIoTClient 43:4c1e4e94cdd3 1417 result = __FAILURE__;
AzureIoTClient 43:4c1e4e94cdd3 1418 }
AzureIoTClient 4:98007eb79fa8 1419 else
AzureIoTClient 4:98007eb79fa8 1420 {
AzureIoTClient 4:98007eb79fa8 1421 if (condition_value != NULL)
AzureIoTClient 4:98007eb79fa8 1422 {
AzureIoTClient 43:4c1e4e94cdd3 1423 close_connection_with_error(connection, condition_value, description, info);
AzureIoTClient 4:98007eb79fa8 1424 }
AzureIoTClient 4:98007eb79fa8 1425 else
AzureIoTClient 4:98007eb79fa8 1426 {
AzureIoTClient 28:add19eb7defa 1427 if (send_close_frame(connection, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1428 {
AzureIoTClient 28:add19eb7defa 1429 LogError("Sending CLOSE frame failed");
AzureIoTClient 28:add19eb7defa 1430 }
AzureIoTClient 24:2c59c2d43ebf 1431
AzureIoTClient 4:98007eb79fa8 1432 connection_set_state(connection, CONNECTION_STATE_END);
AzureIoTClient 4:98007eb79fa8 1433 }
Azure.IoT Build 0:6ae2f7bca550 1434
AzureIoTClient 28:add19eb7defa 1435 if (xio_close(connection->io, NULL, NULL) != 0)
AzureIoTClient 28:add19eb7defa 1436 {
AzureIoTClient 28:add19eb7defa 1437 LogError("xio_close failed");
AzureIoTClient 28:add19eb7defa 1438 }
AzureIoTClient 24:2c59c2d43ebf 1439
AzureIoTClient 28:add19eb7defa 1440 connection->is_underlying_io_open = 1;
Azure.IoT Build 0:6ae2f7bca550 1441
Azure.IoT Build 0:6ae2f7bca550 1442 result = 0;
AzureIoTClient 4:98007eb79fa8 1443 }
Azure.IoT Build 0:6ae2f7bca550 1444
AzureIoTClient 4:98007eb79fa8 1445 return result;
Azure.IoT Build 0:6ae2f7bca550 1446 }
Azure.IoT Build 0:6ae2f7bca550 1447
Azure.IoT Build 0:6ae2f7bca550 1448 int connection_set_max_frame_size(CONNECTION_HANDLE connection, uint32_t max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1449 {
AzureIoTClient 4:98007eb79fa8 1450 int result;
Azure.IoT Build 0:6ae2f7bca550 1451
AzureIoTClient 43:4c1e4e94cdd3 1452 /* Codes_S_R_S_CONNECTION_01_163: [If connection is NULL, connection_set_max_frame_size shall fail and return a non-zero value.] */
AzureIoTClient 28:add19eb7defa 1453 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1454 {
AzureIoTClient 28:add19eb7defa 1455 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1456 result = __FAILURE__;
AzureIoTClient 28:add19eb7defa 1457 }
AzureIoTClient 43:4c1e4e94cdd3 1458 /* Codes_S_R_S_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 43:4c1e4e94cdd3 1459 /* Codes_S_R_S_CONNECTION_01_167: [Both peers MUST accept frames of up to 512 (MIN-MAX-FRAME-SIZE) octets.] */
AzureIoTClient 28:add19eb7defa 1460 else if (max_frame_size < 512)
AzureIoTClient 28:add19eb7defa 1461 {
AzureIoTClient 28:add19eb7defa 1462 LogError("max_frame_size too small");
AzureIoTClient 28:add19eb7defa 1463 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1464 }
AzureIoTClient 4:98007eb79fa8 1465 else
AzureIoTClient 4:98007eb79fa8 1466 {
AzureIoTClient 43:4c1e4e94cdd3 1467 /* Codes_S_R_S_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 1468 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1469 {
AzureIoTClient 28:add19eb7defa 1470 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1471 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1472 }
AzureIoTClient 4:98007eb79fa8 1473 else
AzureIoTClient 4:98007eb79fa8 1474 {
AzureIoTClient 43:4c1e4e94cdd3 1475 /* Codes_S_R_S_CONNECTION_01_148: [connection_set_max_frame_size shall set the max_frame_size associated with a connection.] */
AzureIoTClient 43:4c1e4e94cdd3 1476 /* Codes_S_R_S_CONNECTION_01_164: [If connection_set_max_frame_size fails, the previous max_frame_size setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1477 connection->max_frame_size = max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1478
AzureIoTClient 43:4c1e4e94cdd3 1479 /* Codes_S_R_S_CONNECTION_01_149: [On success connection_set_max_frame_size shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1480 result = 0;
AzureIoTClient 4:98007eb79fa8 1481 }
AzureIoTClient 4:98007eb79fa8 1482 }
Azure.IoT Build 0:6ae2f7bca550 1483
AzureIoTClient 4:98007eb79fa8 1484 return result;
Azure.IoT Build 0:6ae2f7bca550 1485 }
Azure.IoT Build 0:6ae2f7bca550 1486
Azure.IoT Build 0:6ae2f7bca550 1487 int connection_get_max_frame_size(CONNECTION_HANDLE connection, uint32_t* max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1488 {
AzureIoTClient 4:98007eb79fa8 1489 int result;
Azure.IoT Build 0:6ae2f7bca550 1490
AzureIoTClient 43:4c1e4e94cdd3 1491 /* Codes_S_R_S_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 1492 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1493 (max_frame_size == NULL))
AzureIoTClient 4:98007eb79fa8 1494 {
AzureIoTClient 28:add19eb7defa 1495 LogError("Bad arguments: connection = %p, max_frame_size = %p",
AzureIoTClient 28:add19eb7defa 1496 connection, max_frame_size);
AzureIoTClient 28:add19eb7defa 1497 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1498 }
AzureIoTClient 4:98007eb79fa8 1499 else
AzureIoTClient 4:98007eb79fa8 1500 {
AzureIoTClient 43:4c1e4e94cdd3 1501 /* Codes_S_R_S_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 1502 *max_frame_size = connection->max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1503
AzureIoTClient 43:4c1e4e94cdd3 1504 /* Codes_S_R_S_CONNECTION_01_169: [On success, connection_get_max_frame_size shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1505 result = 0;
AzureIoTClient 4:98007eb79fa8 1506 }
Azure.IoT Build 0:6ae2f7bca550 1507
AzureIoTClient 4:98007eb79fa8 1508 return result;
Azure.IoT Build 0:6ae2f7bca550 1509 }
Azure.IoT Build 0:6ae2f7bca550 1510
Azure.IoT Build 0:6ae2f7bca550 1511 int connection_set_channel_max(CONNECTION_HANDLE connection, uint16_t channel_max)
Azure.IoT Build 0:6ae2f7bca550 1512 {
AzureIoTClient 4:98007eb79fa8 1513 int result;
Azure.IoT Build 0:6ae2f7bca550 1514
AzureIoTClient 43:4c1e4e94cdd3 1515 /* Codes_S_R_S_CONNECTION_01_181: [If connection is NULL then connection_set_channel_max shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1516 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1517 {
AzureIoTClient 28:add19eb7defa 1518 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1519 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1520 }
AzureIoTClient 4:98007eb79fa8 1521 else
AzureIoTClient 4:98007eb79fa8 1522 {
AzureIoTClient 43:4c1e4e94cdd3 1523 /* Codes_S_R_S_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 1524 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1525 {
AzureIoTClient 28:add19eb7defa 1526 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1527 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1528 }
AzureIoTClient 4:98007eb79fa8 1529 else
AzureIoTClient 4:98007eb79fa8 1530 {
AzureIoTClient 43:4c1e4e94cdd3 1531 /* Codes_S_R_S_CONNECTION_01_153: [connection_set_channel_max shall set the channel_max associated with a connection.] */
AzureIoTClient 43:4c1e4e94cdd3 1532 /* Codes_S_R_S_CONNECTION_01_165: [If connection_set_channel_max fails, the previous channel_max setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1533 connection->channel_max = channel_max;
Azure.IoT Build 0:6ae2f7bca550 1534
AzureIoTClient 43:4c1e4e94cdd3 1535 /* Codes_S_R_S_CONNECTION_01_154: [On success connection_set_channel_max shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1536 result = 0;
AzureIoTClient 4:98007eb79fa8 1537 }
AzureIoTClient 4:98007eb79fa8 1538 }
Azure.IoT Build 0:6ae2f7bca550 1539
AzureIoTClient 4:98007eb79fa8 1540 return result;
Azure.IoT Build 0:6ae2f7bca550 1541 }
Azure.IoT Build 0:6ae2f7bca550 1542
Azure.IoT Build 0:6ae2f7bca550 1543 int connection_get_channel_max(CONNECTION_HANDLE connection, uint16_t* channel_max)
Azure.IoT Build 0:6ae2f7bca550 1544 {
AzureIoTClient 4:98007eb79fa8 1545 int result;
Azure.IoT Build 0:6ae2f7bca550 1546
AzureIoTClient 43:4c1e4e94cdd3 1547 /* Codes_S_R_S_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 1548 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1549 (channel_max == NULL))
AzureIoTClient 4:98007eb79fa8 1550 {
AzureIoTClient 28:add19eb7defa 1551 LogError("Bad arguments: connection = %p, channel_max = %p",
AzureIoTClient 28:add19eb7defa 1552 connection, channel_max);
AzureIoTClient 28:add19eb7defa 1553 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1554 }
AzureIoTClient 4:98007eb79fa8 1555 else
AzureIoTClient 4:98007eb79fa8 1556 {
AzureIoTClient 43:4c1e4e94cdd3 1557 /* Codes_S_R_S_CONNECTION_01_182: [connection_get_channel_max shall return in the channel_max argument the current channel_max setting.] */
AzureIoTClient 4:98007eb79fa8 1558 *channel_max = connection->channel_max;
Azure.IoT Build 0:6ae2f7bca550 1559
AzureIoTClient 43:4c1e4e94cdd3 1560 /* Codes_S_R_S_CONNECTION_01_183: [On success, connection_get_channel_max shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1561 result = 0;
AzureIoTClient 4:98007eb79fa8 1562 }
Azure.IoT Build 0:6ae2f7bca550 1563
AzureIoTClient 4:98007eb79fa8 1564 return result;
Azure.IoT Build 0:6ae2f7bca550 1565 }
Azure.IoT Build 0:6ae2f7bca550 1566
Azure.IoT Build 0:6ae2f7bca550 1567 int connection_set_idle_timeout(CONNECTION_HANDLE connection, milliseconds idle_timeout)
Azure.IoT Build 0:6ae2f7bca550 1568 {
AzureIoTClient 4:98007eb79fa8 1569 int result;
Azure.IoT Build 0:6ae2f7bca550 1570
AzureIoTClient 43:4c1e4e94cdd3 1571 /* Codes_S_R_S_CONNECTION_01_191: [If connection is NULL, connection_set_idle_timeout shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 1572 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1573 {
AzureIoTClient 28:add19eb7defa 1574 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1575 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1576 }
AzureIoTClient 4:98007eb79fa8 1577 else
AzureIoTClient 4:98007eb79fa8 1578 {
AzureIoTClient 43:4c1e4e94cdd3 1579 /* Codes_S_R_S_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 1580 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 4:98007eb79fa8 1581 {
AzureIoTClient 28:add19eb7defa 1582 LogError("Connection already open");
AzureIoTClient 28:add19eb7defa 1583 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1584 }
AzureIoTClient 4:98007eb79fa8 1585 else
AzureIoTClient 4:98007eb79fa8 1586 {
AzureIoTClient 43:4c1e4e94cdd3 1587 /* Codes_S_R_S_CONNECTION_01_159: [connection_set_idle_timeout shall set the idle_timeout associated with a connection.] */
AzureIoTClient 43:4c1e4e94cdd3 1588 /* Codes_S_R_S_CONNECTION_01_166: [If connection_set_idle_timeout fails, the previous idle_timeout setting shall be retained.] */
AzureIoTClient 4:98007eb79fa8 1589 connection->idle_timeout = idle_timeout;
AzureIoTClient 4:98007eb79fa8 1590 connection->idle_timeout_specified = true;
Azure.IoT Build 0:6ae2f7bca550 1591
AzureIoTClient 43:4c1e4e94cdd3 1592 /* Codes_S_R_S_CONNECTION_01_160: [On success connection_set_idle_timeout shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1593 result = 0;
AzureIoTClient 4:98007eb79fa8 1594 }
AzureIoTClient 4:98007eb79fa8 1595 }
Azure.IoT Build 0:6ae2f7bca550 1596
AzureIoTClient 4:98007eb79fa8 1597 return result;
Azure.IoT Build 0:6ae2f7bca550 1598 }
Azure.IoT Build 0:6ae2f7bca550 1599
Azure.IoT Build 0:6ae2f7bca550 1600 int connection_get_idle_timeout(CONNECTION_HANDLE connection, milliseconds* idle_timeout)
Azure.IoT Build 0:6ae2f7bca550 1601 {
AzureIoTClient 4:98007eb79fa8 1602 int result;
Azure.IoT Build 0:6ae2f7bca550 1603
AzureIoTClient 43:4c1e4e94cdd3 1604 /* Codes_S_R_S_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 1605 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1606 (idle_timeout == NULL))
AzureIoTClient 4:98007eb79fa8 1607 {
AzureIoTClient 28:add19eb7defa 1608 LogError("Bad arguments: connection = %p, idle_timeout = %p",
AzureIoTClient 28:add19eb7defa 1609 connection, idle_timeout);
AzureIoTClient 28:add19eb7defa 1610 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1611 }
AzureIoTClient 4:98007eb79fa8 1612 else
AzureIoTClient 4:98007eb79fa8 1613 {
AzureIoTClient 43:4c1e4e94cdd3 1614 /* Codes_S_R_S_CONNECTION_01_188: [connection_get_idle_timeout shall return in the idle_timeout argument the current idle_timeout setting.] */
AzureIoTClient 4:98007eb79fa8 1615 *idle_timeout = connection->idle_timeout;
Azure.IoT Build 0:6ae2f7bca550 1616
AzureIoTClient 43:4c1e4e94cdd3 1617 /* Codes_S_R_S_CONNECTION_01_189: [On success, connection_get_idle_timeout shall return 0.] */
AzureIoTClient 4:98007eb79fa8 1618 result = 0;
AzureIoTClient 4:98007eb79fa8 1619 }
Azure.IoT Build 0:6ae2f7bca550 1620
AzureIoTClient 4:98007eb79fa8 1621 return result;
Azure.IoT Build 0:6ae2f7bca550 1622 }
Azure.IoT Build 0:6ae2f7bca550 1623
AzureIoTClient 41:0e723f9cbd89 1624 int connection_set_properties(CONNECTION_HANDLE connection, fields properties)
AzureIoTClient 41:0e723f9cbd89 1625 {
AzureIoTClient 41:0e723f9cbd89 1626 int result;
AzureIoTClient 41:0e723f9cbd89 1627
AzureIoTClient 43:4c1e4e94cdd3 1628 /* Codes_S_R_S_CONNECTION_01_261: [If connection is NULL, connection_set_properties shall fail and return a non-zero value.] */
AzureIoTClient 41:0e723f9cbd89 1629 if (connection == NULL)
AzureIoTClient 41:0e723f9cbd89 1630 {
AzureIoTClient 41:0e723f9cbd89 1631 LogError("NULL connection");
AzureIoTClient 41:0e723f9cbd89 1632 result = __FAILURE__;
AzureIoTClient 41:0e723f9cbd89 1633 }
AzureIoTClient 41:0e723f9cbd89 1634 else
AzureIoTClient 41:0e723f9cbd89 1635 {
AzureIoTClient 43:4c1e4e94cdd3 1636 /* Codes_S_R_S_CONNECTION_01_262: [If connection_set_properties is called after the initial Open frame has been sent, it shall fail and return a non-zero value.] */
AzureIoTClient 41:0e723f9cbd89 1637 if (connection->connection_state != CONNECTION_STATE_START)
AzureIoTClient 41:0e723f9cbd89 1638 {
AzureIoTClient 41:0e723f9cbd89 1639 LogError("Connection already open");
AzureIoTClient 41:0e723f9cbd89 1640 result = __FAILURE__;
AzureIoTClient 41:0e723f9cbd89 1641 }
AzureIoTClient 41:0e723f9cbd89 1642 else
AzureIoTClient 41:0e723f9cbd89 1643 {
AzureIoTClient 41:0e723f9cbd89 1644 if (properties == NULL)
AzureIoTClient 41:0e723f9cbd89 1645 {
AzureIoTClient 43:4c1e4e94cdd3 1646 /* Codes_S_R_S_CONNECTION_01_263: [ If `properties` is NULL, the previously stored properties associated with `connection` shall be freed. ]*/
AzureIoTClient 41:0e723f9cbd89 1647 if (connection->properties != NULL)
AzureIoTClient 41:0e723f9cbd89 1648 {
AzureIoTClient 41:0e723f9cbd89 1649 fields_destroy(connection->properties);
AzureIoTClient 41:0e723f9cbd89 1650 connection->properties = NULL;
AzureIoTClient 41:0e723f9cbd89 1651 }
AzureIoTClient 41:0e723f9cbd89 1652
AzureIoTClient 43:4c1e4e94cdd3 1653 /* Codes_S_R_S_CONNECTION_01_264: [ On success it shall return 0. ]*/
AzureIoTClient 41:0e723f9cbd89 1654 result = 0;
AzureIoTClient 41:0e723f9cbd89 1655 }
AzureIoTClient 41:0e723f9cbd89 1656 else
AzureIoTClient 41:0e723f9cbd89 1657 {
AzureIoTClient 41:0e723f9cbd89 1658 fields new_properties;
AzureIoTClient 41:0e723f9cbd89 1659
AzureIoTClient 43:4c1e4e94cdd3 1660 /* Codes_S_R_S_CONNECTION_01_265: [ `connection_set_properties` shall copy the contents of `properties` as the properties contents for the connection instance identified by `connection`. ]*/
AzureIoTClient 43:4c1e4e94cdd3 1661 /* Codes_S_R_S_CONNECTION_01_266: [ Cloning the properties shall be done by calling `fields_clone`. ]*/
AzureIoTClient 41:0e723f9cbd89 1662 new_properties = fields_clone(properties);
AzureIoTClient 41:0e723f9cbd89 1663 if (new_properties == NULL)
AzureIoTClient 41:0e723f9cbd89 1664 {
AzureIoTClient 43:4c1e4e94cdd3 1665 /* Codes_S_R_S_CONNECTION_01_267: [ If `fields_clone` fails, `connection_set_properties` shall fail and return a non-zero value. ]*/
AzureIoTClient 41:0e723f9cbd89 1666 LogError("Cannot clone connection properties");
AzureIoTClient 41:0e723f9cbd89 1667 result = __FAILURE__;
AzureIoTClient 41:0e723f9cbd89 1668 }
AzureIoTClient 41:0e723f9cbd89 1669 else
AzureIoTClient 41:0e723f9cbd89 1670 {
AzureIoTClient 43:4c1e4e94cdd3 1671 /* Codes_S_R_S_CONNECTION_01_268: [ If setting the properties fails, the previous value shall be preserved. ]*/
AzureIoTClient 41:0e723f9cbd89 1672 /* Only do the free of the previous value if we could clone the new one*/
AzureIoTClient 41:0e723f9cbd89 1673 if (connection->properties != NULL)
AzureIoTClient 41:0e723f9cbd89 1674 {
AzureIoTClient 41:0e723f9cbd89 1675 fields_destroy(connection->properties);
AzureIoTClient 41:0e723f9cbd89 1676 }
AzureIoTClient 41:0e723f9cbd89 1677
AzureIoTClient 41:0e723f9cbd89 1678 connection->properties = new_properties;
AzureIoTClient 41:0e723f9cbd89 1679
AzureIoTClient 43:4c1e4e94cdd3 1680 /* Codes_S_R_S_CONNECTION_01_264: [ On success it shall return 0. ]*/
AzureIoTClient 41:0e723f9cbd89 1681 result = 0;
AzureIoTClient 41:0e723f9cbd89 1682 }
AzureIoTClient 41:0e723f9cbd89 1683 }
AzureIoTClient 41:0e723f9cbd89 1684 }
AzureIoTClient 41:0e723f9cbd89 1685 }
AzureIoTClient 41:0e723f9cbd89 1686
AzureIoTClient 41:0e723f9cbd89 1687 return result;
AzureIoTClient 41:0e723f9cbd89 1688 }
AzureIoTClient 41:0e723f9cbd89 1689
AzureIoTClient 41:0e723f9cbd89 1690 int connection_get_properties(CONNECTION_HANDLE connection, fields* properties)
AzureIoTClient 41:0e723f9cbd89 1691 {
AzureIoTClient 41:0e723f9cbd89 1692 int result;
AzureIoTClient 41:0e723f9cbd89 1693
AzureIoTClient 43:4c1e4e94cdd3 1694 /* Codes_S_R_S_CONNECTION_01_269: [If connection or properties is NULL, connection_get_properties shall fail and return a non-zero value.] */
AzureIoTClient 41:0e723f9cbd89 1695 if ((connection == NULL) ||
AzureIoTClient 41:0e723f9cbd89 1696 (properties == NULL))
AzureIoTClient 41:0e723f9cbd89 1697 {
AzureIoTClient 41:0e723f9cbd89 1698 LogError("Bad arguments: connection = %p, properties = %p",
AzureIoTClient 41:0e723f9cbd89 1699 connection, properties);
AzureIoTClient 41:0e723f9cbd89 1700 result = __FAILURE__;
AzureIoTClient 41:0e723f9cbd89 1701 }
AzureIoTClient 41:0e723f9cbd89 1702 else
AzureIoTClient 41:0e723f9cbd89 1703 {
AzureIoTClient 41:0e723f9cbd89 1704 if (connection->properties == NULL)
AzureIoTClient 41:0e723f9cbd89 1705 {
AzureIoTClient 43:4c1e4e94cdd3 1706 /* Codes_S_R_S_CONNECTION_01_270: [ If no properties have been set, `connection_get_properties` shall set `properties` to NULL. ]*/
AzureIoTClient 41:0e723f9cbd89 1707 *properties = NULL;
AzureIoTClient 41:0e723f9cbd89 1708
AzureIoTClient 43:4c1e4e94cdd3 1709 /* Codes_S_R_S_CONNECTION_01_271: [On success, connection_get_properties shall return 0.] */
AzureIoTClient 41:0e723f9cbd89 1710 result = 0;
AzureIoTClient 41:0e723f9cbd89 1711 }
AzureIoTClient 41:0e723f9cbd89 1712 else
AzureIoTClient 41:0e723f9cbd89 1713 {
AzureIoTClient 43:4c1e4e94cdd3 1714 /* Codes_S_R_S_CONNECTION_01_272: [connection_get_properties shall return in the properties argument the current properties setting.] */
AzureIoTClient 43:4c1e4e94cdd3 1715 /* Codes_S_R_S_CONNECTION_01_273: [ Cloning the properties shall be done by calling `fields_clone`. ]*/
AzureIoTClient 41:0e723f9cbd89 1716 *properties = fields_clone(connection->properties);
AzureIoTClient 41:0e723f9cbd89 1717 if (*properties == NULL)
AzureIoTClient 41:0e723f9cbd89 1718 {
AzureIoTClient 43:4c1e4e94cdd3 1719 /* Codes_S_R_S_CONNECTION_01_274: [ If `fields_clone` fails, `connection_get_properties` shall fail and return a non-zero value. ]*/
AzureIoTClient 41:0e723f9cbd89 1720 LogError("Cannot clone properties");
AzureIoTClient 41:0e723f9cbd89 1721 result = __FAILURE__;
AzureIoTClient 41:0e723f9cbd89 1722 }
AzureIoTClient 41:0e723f9cbd89 1723 else
AzureIoTClient 41:0e723f9cbd89 1724 {
AzureIoTClient 43:4c1e4e94cdd3 1725 /* Codes_S_R_S_CONNECTION_01_271: [On success, connection_get_properties shall return 0.] */
AzureIoTClient 41:0e723f9cbd89 1726 result = 0;
AzureIoTClient 41:0e723f9cbd89 1727 }
AzureIoTClient 41:0e723f9cbd89 1728 }
AzureIoTClient 41:0e723f9cbd89 1729 }
AzureIoTClient 41:0e723f9cbd89 1730
AzureIoTClient 41:0e723f9cbd89 1731 return result;
AzureIoTClient 41:0e723f9cbd89 1732 }
AzureIoTClient 41:0e723f9cbd89 1733
Azure.IoT Build 0:6ae2f7bca550 1734 int connection_get_remote_max_frame_size(CONNECTION_HANDLE connection, uint32_t* remote_max_frame_size)
Azure.IoT Build 0:6ae2f7bca550 1735 {
AzureIoTClient 4:98007eb79fa8 1736 int result;
Azure.IoT Build 0:6ae2f7bca550 1737
AzureIoTClient 4:98007eb79fa8 1738 if ((connection == NULL) ||
AzureIoTClient 4:98007eb79fa8 1739 (remote_max_frame_size == NULL))
AzureIoTClient 4:98007eb79fa8 1740 {
AzureIoTClient 28:add19eb7defa 1741 LogError("Bad arguments: connection = %p, remote_max_frame_size = %p",
AzureIoTClient 28:add19eb7defa 1742 connection, remote_max_frame_size);
AzureIoTClient 28:add19eb7defa 1743 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1744 }
AzureIoTClient 4:98007eb79fa8 1745 else
AzureIoTClient 4:98007eb79fa8 1746 {
AzureIoTClient 4:98007eb79fa8 1747 *remote_max_frame_size = connection->remote_max_frame_size;
Azure.IoT Build 0:6ae2f7bca550 1748
AzureIoTClient 4:98007eb79fa8 1749 result = 0;
AzureIoTClient 4:98007eb79fa8 1750 }
Azure.IoT Build 0:6ae2f7bca550 1751
AzureIoTClient 4:98007eb79fa8 1752 return result;
Azure.IoT Build 0:6ae2f7bca550 1753 }
Azure.IoT Build 0:6ae2f7bca550 1754
AzureIoTClient 1:eab586236bfe 1755 uint64_t connection_handle_deadlines(CONNECTION_HANDLE connection)
AzureIoTClient 1:eab586236bfe 1756 {
AzureIoTClient 35:d0bed2404ee9 1757 uint64_t local_deadline = (uint64_t)-1;
AzureIoTClient 1:eab586236bfe 1758 uint64_t remote_deadline = (uint64_t)-1;
AzureIoTClient 1:eab586236bfe 1759
AzureIoTClient 28:add19eb7defa 1760 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1761 {
AzureIoTClient 28:add19eb7defa 1762 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1763 }
AzureIoTClient 28:add19eb7defa 1764 else
AzureIoTClient 28:add19eb7defa 1765 {
Azure.IoT.Build 14:0b0e28c75ded 1766 tickcounter_ms_t current_ms;
AzureIoTClient 1:eab586236bfe 1767
AzureIoTClient 1:eab586236bfe 1768 if (tickcounter_get_current_ms(connection->tick_counter, &current_ms) != 0)
AzureIoTClient 1:eab586236bfe 1769 {
AzureIoTClient 28:add19eb7defa 1770 LogError("Could not get tick counter value");
AzureIoTClient 43:4c1e4e94cdd3 1771 close_connection_with_error(connection, "amqp:internal-error", "Could not get tick count", NULL);
AzureIoTClient 1:eab586236bfe 1772 }
AzureIoTClient 1:eab586236bfe 1773 else
AzureIoTClient 1:eab586236bfe 1774 {
AzureIoTClient 1:eab586236bfe 1775 if (connection->idle_timeout_specified && (connection->idle_timeout != 0))
AzureIoTClient 1:eab586236bfe 1776 {
AzureIoTClient 1:eab586236bfe 1777 /* Calculate time until configured idle timeout expires */
AzureIoTClient 1:eab586236bfe 1778
AzureIoTClient 1:eab586236bfe 1779 uint64_t time_since_last_received = current_ms - connection->last_frame_received_time;
AzureIoTClient 1:eab586236bfe 1780 if (time_since_last_received < connection->idle_timeout)
AzureIoTClient 1:eab586236bfe 1781 {
AzureIoTClient 1:eab586236bfe 1782 local_deadline = connection->idle_timeout - time_since_last_received;
AzureIoTClient 1:eab586236bfe 1783 }
AzureIoTClient 1:eab586236bfe 1784 else
AzureIoTClient 1:eab586236bfe 1785 {
AzureIoTClient 1:eab586236bfe 1786 local_deadline = 0;
AzureIoTClient 1:eab586236bfe 1787
AzureIoTClient 1:eab586236bfe 1788 /* close connection */
AzureIoTClient 43:4c1e4e94cdd3 1789 close_connection_with_error(connection, "amqp:internal-error", "No frame received for the idle timeout", NULL);
AzureIoTClient 1:eab586236bfe 1790 }
AzureIoTClient 1:eab586236bfe 1791 }
AzureIoTClient 1:eab586236bfe 1792
AzureIoTClient 1:eab586236bfe 1793 if (local_deadline != 0 && connection->remote_idle_timeout != 0)
AzureIoTClient 1:eab586236bfe 1794 {
AzureIoTClient 1:eab586236bfe 1795 /* Calculate time until remote idle timeout expires */
AzureIoTClient 1:eab586236bfe 1796
AzureIoTClient 35:d0bed2404ee9 1797 uint64_t remote_idle_timeout = connection->remote_idle_timeout_send_frame_millisecond;
AzureIoTClient 1:eab586236bfe 1798 uint64_t time_since_last_sent = current_ms - connection->last_frame_sent_time;
AzureIoTClient 1:eab586236bfe 1799
AzureIoTClient 1:eab586236bfe 1800 if (time_since_last_sent < remote_idle_timeout)
AzureIoTClient 1:eab586236bfe 1801 {
AzureIoTClient 1:eab586236bfe 1802 remote_deadline = remote_idle_timeout - time_since_last_sent;
AzureIoTClient 1:eab586236bfe 1803 }
AzureIoTClient 1:eab586236bfe 1804 else
AzureIoTClient 1:eab586236bfe 1805 {
AzureIoTClient 1:eab586236bfe 1806 connection->on_send_complete = NULL;
AzureIoTClient 1:eab586236bfe 1807 if (amqp_frame_codec_encode_empty_frame(connection->amqp_frame_codec, 0, on_bytes_encoded, connection) != 0)
AzureIoTClient 1:eab586236bfe 1808 {
AzureIoTClient 28:add19eb7defa 1809 LogError("Encoding the empty frame failed");
AzureIoTClient 28:add19eb7defa 1810 /* close connection */
AzureIoTClient 43:4c1e4e94cdd3 1811 close_connection_with_error(connection, "amqp:internal-error", "Cannot send empty frame", NULL);
AzureIoTClient 1:eab586236bfe 1812 }
AzureIoTClient 1:eab586236bfe 1813 else
AzureIoTClient 1:eab586236bfe 1814 {
AzureIoTClient 6:641a9672db08 1815 if (connection->is_trace_on == 1)
AzureIoTClient 6:641a9672db08 1816 {
AzureIoTClient 16:22a72cf8e416 1817 LOG(AZ_LOG_TRACE, LOG_LINE, "-> Empty frame");
AzureIoTClient 6:641a9672db08 1818 }
AzureIoTClient 1:eab586236bfe 1819
AzureIoTClient 1:eab586236bfe 1820 connection->last_frame_sent_time = current_ms;
AzureIoTClient 1:eab586236bfe 1821
AzureIoTClient 1:eab586236bfe 1822 remote_deadline = remote_idle_timeout;
AzureIoTClient 1:eab586236bfe 1823 }
AzureIoTClient 1:eab586236bfe 1824 }
AzureIoTClient 1:eab586236bfe 1825 }
AzureIoTClient 1:eab586236bfe 1826 }
AzureIoTClient 1:eab586236bfe 1827 }
AzureIoTClient 1:eab586236bfe 1828
AzureIoTClient 1:eab586236bfe 1829 /* Return the shorter of each deadline, or 0 to indicate connection closed */
AzureIoTClient 1:eab586236bfe 1830 return local_deadline > remote_deadline ? remote_deadline : local_deadline;
AzureIoTClient 1:eab586236bfe 1831 }
AzureIoTClient 1:eab586236bfe 1832
Azure.IoT Build 0:6ae2f7bca550 1833 void connection_dowork(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1834 {
AzureIoTClient 43:4c1e4e94cdd3 1835 /* Codes_S_R_S_CONNECTION_01_078: [If handle is NULL, connection_dowork shall do nothing.] */
AzureIoTClient 28:add19eb7defa 1836 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 1837 {
AzureIoTClient 28:add19eb7defa 1838 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1839 }
AzureIoTClient 28:add19eb7defa 1840 else
AzureIoTClient 28:add19eb7defa 1841 {
AzureIoTClient 1:eab586236bfe 1842 if (connection_handle_deadlines(connection) > 0)
AzureIoTClient 1:eab586236bfe 1843 {
AzureIoTClient 43:4c1e4e94cdd3 1844 /* Codes_S_R_S_CONNECTION_01_076: [connection_dowork shall schedule the underlying IO interface to do its work by calling xio_dowork.] */
AzureIoTClient 1:eab586236bfe 1845 xio_dowork(connection->io);
AzureIoTClient 1:eab586236bfe 1846 }
AzureIoTClient 1:eab586236bfe 1847 }
Azure.IoT Build 0:6ae2f7bca550 1848 }
Azure.IoT Build 0:6ae2f7bca550 1849
Azure.IoT Build 0:6ae2f7bca550 1850 ENDPOINT_HANDLE connection_create_endpoint(CONNECTION_HANDLE connection)
Azure.IoT Build 0:6ae2f7bca550 1851 {
AzureIoTClient 28:add19eb7defa 1852 ENDPOINT_HANDLE result;
Azure.IoT Build 0:6ae2f7bca550 1853
AzureIoTClient 43:4c1e4e94cdd3 1854 /* Codes_S_R_S_CONNECTION_01_113: [If connection, on_endpoint_frame_received or on_connection_state_changed is NULL, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 43:4c1e4e94cdd3 1855 /* Codes_S_R_S_CONNECTION_01_193: [The context argument shall be allowed to be NULL.] */
AzureIoTClient 4:98007eb79fa8 1856 if (connection == NULL)
AzureIoTClient 4:98007eb79fa8 1857 {
AzureIoTClient 28:add19eb7defa 1858 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 1859 result = NULL;
AzureIoTClient 4:98007eb79fa8 1860 }
AzureIoTClient 4:98007eb79fa8 1861 else
AzureIoTClient 4:98007eb79fa8 1862 {
AzureIoTClient 43:4c1e4e94cdd3 1863 /* Codes_S_R_S_CONNECTION_01_115: [If no more endpoints can be created due to all channels being used, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 4:98007eb79fa8 1864 if (connection->endpoint_count >= connection->channel_max)
AzureIoTClient 4:98007eb79fa8 1865 {
AzureIoTClient 4:98007eb79fa8 1866 result = NULL;
AzureIoTClient 4:98007eb79fa8 1867 }
AzureIoTClient 4:98007eb79fa8 1868 else
AzureIoTClient 4:98007eb79fa8 1869 {
AzureIoTClient 4:98007eb79fa8 1870 uint32_t i = 0;
Azure.IoT Build 0:6ae2f7bca550 1871
AzureIoTClient 43:4c1e4e94cdd3 1872 /* Codes_S_R_S_CONNECTION_01_128: [The lowest number outgoing channel shall be associated with the newly created endpoint.] */
AzureIoTClient 4:98007eb79fa8 1873 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 1874 {
AzureIoTClient 4:98007eb79fa8 1875 if (connection->endpoints[i]->outgoing_channel > i)
AzureIoTClient 4:98007eb79fa8 1876 {
AzureIoTClient 4:98007eb79fa8 1877 /* found a gap in the sorted endpoint array */
AzureIoTClient 4:98007eb79fa8 1878 break;
AzureIoTClient 4:98007eb79fa8 1879 }
AzureIoTClient 4:98007eb79fa8 1880 }
Azure.IoT Build 0:6ae2f7bca550 1881
AzureIoTClient 43:4c1e4e94cdd3 1882 /* Codes_S_R_S_CONNECTION_01_127: [On success, connection_create_endpoint shall return a non-NULL handle to the newly created endpoint.] */
AzureIoTClient 24:2c59c2d43ebf 1883 result = (ENDPOINT_HANDLE)malloc(sizeof(ENDPOINT_INSTANCE));
AzureIoTClient 43:4c1e4e94cdd3 1884 /* Codes_S_R_S_CONNECTION_01_196: [If memory cannot be allocated for the new endpoint, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 28:add19eb7defa 1885 if (result == NULL)
AzureIoTClient 28:add19eb7defa 1886 {
AzureIoTClient 28:add19eb7defa 1887 LogError("Cannot allocate memory for endpoint");
AzureIoTClient 28:add19eb7defa 1888 }
AzureIoTClient 28:add19eb7defa 1889 else
AzureIoTClient 28:add19eb7defa 1890 {
AzureIoTClient 28:add19eb7defa 1891 ENDPOINT_HANDLE* new_endpoints;
Azure.IoT Build 0:6ae2f7bca550 1892
AzureIoTClient 4:98007eb79fa8 1893 result->on_endpoint_frame_received = NULL;
AzureIoTClient 4:98007eb79fa8 1894 result->on_connection_state_changed = NULL;
AzureIoTClient 4:98007eb79fa8 1895 result->callback_context = NULL;
AzureIoTClient 6:641a9672db08 1896 result->outgoing_channel = (uint16_t)i;
AzureIoTClient 4:98007eb79fa8 1897 result->connection = connection;
Azure.IoT Build 0:6ae2f7bca550 1898
AzureIoTClient 43:4c1e4e94cdd3 1899 /* Codes_S_R_S_CONNECTION_01_197: [The newly created endpoint shall be added to the endpoints list, so that it can be tracked.] */
AzureIoTClient 24:2c59c2d43ebf 1900 new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, sizeof(ENDPOINT_HANDLE) * (connection->endpoint_count + 1));
AzureIoTClient 4:98007eb79fa8 1901 if (new_endpoints == NULL)
AzureIoTClient 4:98007eb79fa8 1902 {
AzureIoTClient 43:4c1e4e94cdd3 1903 /* Tests_S_R_S_CONNECTION_01_198: [If adding the endpoint to the endpoints list tracked by the connection fails, connection_create_endpoint shall fail and return NULL.] */
AzureIoTClient 28:add19eb7defa 1904 LogError("Cannot reallocate memory for connection endpoints");
AzureIoTClient 28:add19eb7defa 1905 free(result);
AzureIoTClient 4:98007eb79fa8 1906 result = NULL;
AzureIoTClient 4:98007eb79fa8 1907 }
AzureIoTClient 4:98007eb79fa8 1908 else
AzureIoTClient 4:98007eb79fa8 1909 {
AzureIoTClient 4:98007eb79fa8 1910 connection->endpoints = new_endpoints;
Azure.IoT Build 0:6ae2f7bca550 1911
AzureIoTClient 4:98007eb79fa8 1912 if (i < connection->endpoint_count)
AzureIoTClient 4:98007eb79fa8 1913 {
AzureIoTClient 4:98007eb79fa8 1914 (void)memmove(&connection->endpoints[i + 1], &connection->endpoints[i], sizeof(ENDPOINT_INSTANCE*) * (connection->endpoint_count - i));
AzureIoTClient 4:98007eb79fa8 1915 }
Azure.IoT Build 0:6ae2f7bca550 1916
AzureIoTClient 4:98007eb79fa8 1917 connection->endpoints[i] = result;
AzureIoTClient 4:98007eb79fa8 1918 connection->endpoint_count++;
Azure.IoT Build 0:6ae2f7bca550 1919
AzureIoTClient 43:4c1e4e94cdd3 1920 /* Codes_S_R_S_CONNECTION_01_112: [connection_create_endpoint shall create a new endpoint that can be used by a session.] */
AzureIoTClient 4:98007eb79fa8 1921 }
AzureIoTClient 4:98007eb79fa8 1922 }
AzureIoTClient 4:98007eb79fa8 1923 }
AzureIoTClient 4:98007eb79fa8 1924 }
Azure.IoT Build 0:6ae2f7bca550 1925
AzureIoTClient 4:98007eb79fa8 1926 return result;
Azure.IoT Build 0:6ae2f7bca550 1927 }
Azure.IoT Build 0:6ae2f7bca550 1928
Azure.IoT Build 0:6ae2f7bca550 1929 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 1930 {
AzureIoTClient 4:98007eb79fa8 1931 int result;
Azure.IoT Build 0:6ae2f7bca550 1932
AzureIoTClient 4:98007eb79fa8 1933 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1934 (on_endpoint_frame_received == NULL) ||
AzureIoTClient 4:98007eb79fa8 1935 (on_connection_state_changed == NULL))
AzureIoTClient 4:98007eb79fa8 1936 {
AzureIoTClient 28:add19eb7defa 1937 LogError("Bad arguments: endpoint = %p, on_endpoint_frame_received = %p, on_connection_state_changed = %p",
AzureIoTClient 28:add19eb7defa 1938 endpoint, on_endpoint_frame_received, on_connection_state_changed);
AzureIoTClient 28:add19eb7defa 1939 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1940 }
AzureIoTClient 4:98007eb79fa8 1941 else
AzureIoTClient 4:98007eb79fa8 1942 {
AzureIoTClient 4:98007eb79fa8 1943 endpoint->on_endpoint_frame_received = on_endpoint_frame_received;
AzureIoTClient 4:98007eb79fa8 1944 endpoint->on_connection_state_changed = on_connection_state_changed;
AzureIoTClient 4:98007eb79fa8 1945 endpoint->callback_context = context;
Azure.IoT Build 0:6ae2f7bca550 1946
AzureIoTClient 4:98007eb79fa8 1947 result = 0;
AzureIoTClient 4:98007eb79fa8 1948 }
Azure.IoT Build 0:6ae2f7bca550 1949
AzureIoTClient 4:98007eb79fa8 1950 return result;
Azure.IoT Build 0:6ae2f7bca550 1951 }
Azure.IoT Build 0:6ae2f7bca550 1952
Azure.IoT Build 0:6ae2f7bca550 1953 int connection_endpoint_get_incoming_channel(ENDPOINT_HANDLE endpoint, uint16_t* incoming_channel)
Azure.IoT Build 0:6ae2f7bca550 1954 {
AzureIoTClient 4:98007eb79fa8 1955 int result;
Azure.IoT Build 0:6ae2f7bca550 1956
AzureIoTClient 4:98007eb79fa8 1957 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 1958 (incoming_channel == NULL))
AzureIoTClient 4:98007eb79fa8 1959 {
AzureIoTClient 28:add19eb7defa 1960 LogError("Bad arguments: endpoint = %p, incoming_channel = %p",
AzureIoTClient 28:add19eb7defa 1961 endpoint, incoming_channel);
AzureIoTClient 28:add19eb7defa 1962 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 1963 }
AzureIoTClient 4:98007eb79fa8 1964 else
AzureIoTClient 4:98007eb79fa8 1965 {
AzureIoTClient 4:98007eb79fa8 1966 *incoming_channel = endpoint->incoming_channel;
AzureIoTClient 4:98007eb79fa8 1967 result = 0;
AzureIoTClient 4:98007eb79fa8 1968 }
Azure.IoT Build 0:6ae2f7bca550 1969
AzureIoTClient 4:98007eb79fa8 1970 return result;
Azure.IoT Build 0:6ae2f7bca550 1971 }
Azure.IoT Build 0:6ae2f7bca550 1972
AzureIoTClient 43:4c1e4e94cdd3 1973 /* Codes_S_R_S_CONNECTION_01_129: [connection_destroy_endpoint shall free all resources associated with an endpoint created by connection_create_endpoint.] */
Azure.IoT Build 0:6ae2f7bca550 1974 void connection_destroy_endpoint(ENDPOINT_HANDLE endpoint)
Azure.IoT Build 0:6ae2f7bca550 1975 {
AzureIoTClient 28:add19eb7defa 1976 if (endpoint == NULL)
AzureIoTClient 28:add19eb7defa 1977 {
AzureIoTClient 28:add19eb7defa 1978 LogError("NULL endpoint");
AzureIoTClient 28:add19eb7defa 1979 }
AzureIoTClient 28:add19eb7defa 1980 else
AzureIoTClient 28:add19eb7defa 1981 {
AzureIoTClient 24:2c59c2d43ebf 1982 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)endpoint->connection;
AzureIoTClient 4:98007eb79fa8 1983 size_t i;
Azure.IoT Build 0:6ae2f7bca550 1984
AzureIoTClient 4:98007eb79fa8 1985 for (i = 0; i < connection->endpoint_count; i++)
AzureIoTClient 4:98007eb79fa8 1986 {
AzureIoTClient 4:98007eb79fa8 1987 if (connection->endpoints[i] == endpoint)
AzureIoTClient 4:98007eb79fa8 1988 {
AzureIoTClient 4:98007eb79fa8 1989 break;
AzureIoTClient 4:98007eb79fa8 1990 }
AzureIoTClient 4:98007eb79fa8 1991 }
Azure.IoT Build 0:6ae2f7bca550 1992
AzureIoTClient 43:4c1e4e94cdd3 1993 /* Codes_S_R_S_CONNECTION_01_130: [The outgoing channel associated with the endpoint shall be released by removing the endpoint from the endpoint list.] */
AzureIoTClient 43:4c1e4e94cdd3 1994 /* Codes_S_R_S_CONNECTION_01_131: [Any incoming channel number associated with the endpoint shall be released.] */
AzureIoTClient 45:83b4eda4891c 1995 if (i < connection->endpoint_count)
AzureIoTClient 28:add19eb7defa 1996 {
AzureIoTClient 45:83b4eda4891c 1997 // endpoint found
AzureIoTClient 45:83b4eda4891c 1998 if (connection->endpoint_count == 1)
AzureIoTClient 45:83b4eda4891c 1999 {
AzureIoTClient 45:83b4eda4891c 2000 free(connection->endpoints);
AzureIoTClient 45:83b4eda4891c 2001 connection->endpoints = NULL;
AzureIoTClient 45:83b4eda4891c 2002 connection->endpoint_count = 0;
AzureIoTClient 45:83b4eda4891c 2003 }
AzureIoTClient 45:83b4eda4891c 2004 else
AzureIoTClient 28:add19eb7defa 2005 {
AzureIoTClient 45:83b4eda4891c 2006 ENDPOINT_HANDLE* new_endpoints;
AzureIoTClient 45:83b4eda4891c 2007
AzureIoTClient 45:83b4eda4891c 2008 if ((connection->endpoint_count - i - 1) > 0)
AzureIoTClient 45:83b4eda4891c 2009 {
AzureIoTClient 45:83b4eda4891c 2010 (void)memmove(connection->endpoints + i, connection->endpoints + i + 1, sizeof(ENDPOINT_HANDLE) * (connection->endpoint_count - i - 1));
AzureIoTClient 45:83b4eda4891c 2011 }
Azure.IoT Build 0:6ae2f7bca550 2012
AzureIoTClient 45:83b4eda4891c 2013 new_endpoints = (ENDPOINT_HANDLE*)realloc(connection->endpoints, (connection->endpoint_count - 1) * sizeof(ENDPOINT_HANDLE));
AzureIoTClient 45:83b4eda4891c 2014 if (new_endpoints != NULL)
AzureIoTClient 45:83b4eda4891c 2015 {
AzureIoTClient 45:83b4eda4891c 2016 connection->endpoints = new_endpoints;
AzureIoTClient 45:83b4eda4891c 2017 }
AzureIoTClient 45:83b4eda4891c 2018
AzureIoTClient 45:83b4eda4891c 2019 connection->endpoint_count--;
AzureIoTClient 45:83b4eda4891c 2020 }
AzureIoTClient 28:add19eb7defa 2021 }
Azure.IoT Build 0:6ae2f7bca550 2022
AzureIoTClient 21:f9c433d8e6ca 2023 free(endpoint);
AzureIoTClient 4:98007eb79fa8 2024 }
Azure.IoT Build 0:6ae2f7bca550 2025 }
Azure.IoT Build 0:6ae2f7bca550 2026
AzureIoTClient 43:4c1e4e94cdd3 2027 /* Codes_S_R_S_CONNECTION_01_247: [connection_encode_frame shall send a frame for a certain endpoint.] */
AzureIoTClient 30:0407b2db334c 2028 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 2029 {
AzureIoTClient 4:98007eb79fa8 2030 int result;
Azure.IoT Build 0:6ae2f7bca550 2031
AzureIoTClient 43:4c1e4e94cdd3 2032 /* Codes_S_R_S_CONNECTION_01_249: [If endpoint or performative are NULL, connection_encode_frame shall fail and return a non-zero value.] */
AzureIoTClient 4:98007eb79fa8 2033 if ((endpoint == NULL) ||
AzureIoTClient 4:98007eb79fa8 2034 (performative == NULL))
AzureIoTClient 4:98007eb79fa8 2035 {
AzureIoTClient 28:add19eb7defa 2036 LogError("Bad arguments: endpoint = %p, performative = %p",
AzureIoTClient 28:add19eb7defa 2037 endpoint, performative);
AzureIoTClient 28:add19eb7defa 2038 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 2039 }
AzureIoTClient 4:98007eb79fa8 2040 else
AzureIoTClient 4:98007eb79fa8 2041 {
AzureIoTClient 28:add19eb7defa 2042 CONNECTION_HANDLE connection = (CONNECTION_HANDLE)endpoint->connection;
AzureIoTClient 4:98007eb79fa8 2043 AMQP_FRAME_CODEC_HANDLE amqp_frame_codec = connection->amqp_frame_codec;
Azure.IoT Build 0:6ae2f7bca550 2044
AzureIoTClient 43:4c1e4e94cdd3 2045 /* Codes_S_R_S_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 2046 if (connection->connection_state != CONNECTION_STATE_OPENED)
AzureIoTClient 4:98007eb79fa8 2047 {
AzureIoTClient 28:add19eb7defa 2048 LogError("Connection not open");
AzureIoTClient 28:add19eb7defa 2049 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 2050 }
AzureIoTClient 4:98007eb79fa8 2051 else
AzureIoTClient 4:98007eb79fa8 2052 {
AzureIoTClient 43:4c1e4e94cdd3 2053 /* Codes_S_R_S_CONNECTION_01_255: [The payload size shall be computed based on all the payload chunks passed as argument in payloads.] */
AzureIoTClient 43:4c1e4e94cdd3 2054 /* Codes_S_R_S_CONNECTION_01_250: [connection_encode_frame shall initiate the frame send by calling amqp_frame_codec_begin_encode_frame.] */
AzureIoTClient 43:4c1e4e94cdd3 2055 /* Codes_S_R_S_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 43:4c1e4e94cdd3 2056 /* Codes_S_R_S_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 2057 connection->on_send_complete = on_send_complete;
AzureIoTClient 4:98007eb79fa8 2058 connection->on_send_complete_callback_context = callback_context;
AzureIoTClient 4:98007eb79fa8 2059 if (amqp_frame_codec_encode_frame(amqp_frame_codec, endpoint->outgoing_channel, performative, payloads, payload_count, on_bytes_encoded, connection) != 0)
AzureIoTClient 4:98007eb79fa8 2060 {
AzureIoTClient 43:4c1e4e94cdd3 2061 /* Codes_S_R_S_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 2062 LogError("Encoding AMQP frame failed");
AzureIoTClient 28:add19eb7defa 2063 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 2064 }
AzureIoTClient 4:98007eb79fa8 2065 else
AzureIoTClient 4:98007eb79fa8 2066 {
AzureIoTClient 4:98007eb79fa8 2067 if (connection->is_trace_on == 1)
AzureIoTClient 4:98007eb79fa8 2068 {
Azure.IoT Build 5:ae49385aff34 2069 log_outgoing_frame(performative);
AzureIoTClient 4:98007eb79fa8 2070 }
Azure.IoT Build 5:ae49385aff34 2071
AzureIoTClient 4:98007eb79fa8 2072 if (tickcounter_get_current_ms(connection->tick_counter, &connection->last_frame_sent_time) != 0)
AzureIoTClient 4:98007eb79fa8 2073 {
AzureIoTClient 28:add19eb7defa 2074 LogError("Getting tick counter value failed");
AzureIoTClient 28:add19eb7defa 2075 result = __FAILURE__;
AzureIoTClient 4:98007eb79fa8 2076 }
AzureIoTClient 4:98007eb79fa8 2077 else
AzureIoTClient 4:98007eb79fa8 2078 {
AzureIoTClient 43:4c1e4e94cdd3 2079 /* Codes_S_R_S_CONNECTION_01_248: [On success it shall return 0.] */
AzureIoTClient 4:98007eb79fa8 2080 result = 0;
AzureIoTClient 4:98007eb79fa8 2081 }
AzureIoTClient 4:98007eb79fa8 2082 }
AzureIoTClient 4:98007eb79fa8 2083 }
AzureIoTClient 4:98007eb79fa8 2084 }
Azure.IoT Build 0:6ae2f7bca550 2085
AzureIoTClient 4:98007eb79fa8 2086 return result;
Azure.IoT Build 0:6ae2f7bca550 2087 }
AzureIoTClient 4:98007eb79fa8 2088
AzureIoTClient 24:2c59c2d43ebf 2089 void connection_set_trace(CONNECTION_HANDLE connection, bool trace_on)
AzureIoTClient 4:98007eb79fa8 2090 {
AzureIoTClient 43:4c1e4e94cdd3 2091 /* Codes_S_R_S_CONNECTION_07_002: [If connection is NULL then connection_set_trace shall do nothing.] */
AzureIoTClient 28:add19eb7defa 2092 if (connection == NULL)
AzureIoTClient 28:add19eb7defa 2093 {
AzureIoTClient 28:add19eb7defa 2094 LogError("NULL connection");
AzureIoTClient 28:add19eb7defa 2095 }
AzureIoTClient 28:add19eb7defa 2096 else
AzureIoTClient 28:add19eb7defa 2097 {
AzureIoTClient 43:4c1e4e94cdd3 2098 /* Codes_S_R_S_CONNECTION_07_001: [connection_set_trace shall set the ability to turn on and off trace logging.] */
AzureIoTClient 24:2c59c2d43ebf 2099 connection->is_trace_on = trace_on ? 1 : 0;
AzureIoTClient 4:98007eb79fa8 2100 }
AzureIoTClient 4:98007eb79fa8 2101 }
AzureIoTClient 35:d0bed2404ee9 2102
AzureIoTClient 35:d0bed2404ee9 2103 int connection_set_remote_idle_timeout_empty_frame_send_ratio(CONNECTION_HANDLE connection, double idle_timeout_empty_frame_send_ratio)
AzureIoTClient 35:d0bed2404ee9 2104 {
AzureIoTClient 35:d0bed2404ee9 2105 int result;
AzureIoTClient 35:d0bed2404ee9 2106
AzureIoTClient 35:d0bed2404ee9 2107 if ((connection == NULL) ||
AzureIoTClient 35:d0bed2404ee9 2108 (idle_timeout_empty_frame_send_ratio <= 0.0) ||
AzureIoTClient 35:d0bed2404ee9 2109 (idle_timeout_empty_frame_send_ratio > 1.0))
AzureIoTClient 35:d0bed2404ee9 2110 {
AzureIoTClient 35:d0bed2404ee9 2111 LogError("Bad arguments: connection = %p, idle_timeout_empty_frame_send_ratio = %f",
AzureIoTClient 35:d0bed2404ee9 2112 connection, idle_timeout_empty_frame_send_ratio);
AzureIoTClient 35:d0bed2404ee9 2113 result = __FAILURE__;
AzureIoTClient 35:d0bed2404ee9 2114 }
AzureIoTClient 35:d0bed2404ee9 2115 else
AzureIoTClient 35:d0bed2404ee9 2116 {
AzureIoTClient 35:d0bed2404ee9 2117 connection->idle_timeout_empty_frame_send_ratio = idle_timeout_empty_frame_send_ratio;
AzureIoTClient 35:d0bed2404ee9 2118 result = 0;
AzureIoTClient 35:d0bed2404ee9 2119 }
AzureIoTClient 35:d0bed2404ee9 2120
AzureIoTClient 35:d0bed2404ee9 2121 return result;
AzureIoTClient 35:d0bed2404ee9 2122 }
AzureIoTClient 43:4c1e4e94cdd3 2123
AzureIoTClient 43:4c1e4e94cdd3 2124 ON_CONNECTION_CLOSED_EVENT_SUBSCRIPTION_HANDLE connection_subscribe_on_connection_close_received(CONNECTION_HANDLE connection, ON_CONNECTION_CLOSE_RECEIVED on_connection_close_received, void* context)
AzureIoTClient 43:4c1e4e94cdd3 2125 {
AzureIoTClient 43:4c1e4e94cdd3 2126 ON_CONNECTION_CLOSED_EVENT_SUBSCRIPTION_HANDLE result;
AzureIoTClient 43:4c1e4e94cdd3 2127
AzureIoTClient 43:4c1e4e94cdd3 2128 /* Codes_S_R_S_CONNECTION_01_279: [ `context` shall be allowed to be NULL. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2129
AzureIoTClient 43:4c1e4e94cdd3 2130 /* Codes_S_R_S_CONNECTION_01_277: [ If `connection` is NULL, `connection_subscribe_on_connection_close_received` shall fail and return NULL. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2131 if ((connection == NULL) ||
AzureIoTClient 43:4c1e4e94cdd3 2132 /* Codes_S_R_S_CONNECTION_01_278: [ If `on_connection_close_received` is NULL, `connection_subscribe_on_connection_close_received` shall fail and return NULL. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2133 (on_connection_close_received == NULL))
AzureIoTClient 43:4c1e4e94cdd3 2134 {
AzureIoTClient 43:4c1e4e94cdd3 2135 LogError("Invalid arguments: connection = %p, on_connection_close_received = %p, context = %p",
AzureIoTClient 43:4c1e4e94cdd3 2136 connection, on_connection_close_received, context);
AzureIoTClient 43:4c1e4e94cdd3 2137 result = NULL;
AzureIoTClient 43:4c1e4e94cdd3 2138 }
AzureIoTClient 43:4c1e4e94cdd3 2139 else
AzureIoTClient 43:4c1e4e94cdd3 2140 {
AzureIoTClient 43:4c1e4e94cdd3 2141 if (connection->on_connection_close_received_event_subscription.on_connection_close_received != NULL)
AzureIoTClient 43:4c1e4e94cdd3 2142 {
AzureIoTClient 43:4c1e4e94cdd3 2143 /* Codes_S_R_S_CONNECTION_01_280: [ Only one subscription shall be allowed per connection, if a subsequent second even subscription is done while a subscription is active, `connection_subscribe_on_connection_close_received` shall fail and return NULL. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2144 LogError("Already subscribed for on_connection_close_received events");
AzureIoTClient 43:4c1e4e94cdd3 2145 result = NULL;
AzureIoTClient 43:4c1e4e94cdd3 2146 }
AzureIoTClient 43:4c1e4e94cdd3 2147 else
AzureIoTClient 43:4c1e4e94cdd3 2148 {
AzureIoTClient 43:4c1e4e94cdd3 2149 /* Codes_S_R_S_CONNECTION_01_275: [ `connection_subscribe_on_connection_close_received` shall register the `on_connection_close_received` handler to be triggered whenever a CLOSE performative is received.. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2150 connection->on_connection_close_received_event_subscription.on_connection_close_received = on_connection_close_received;
AzureIoTClient 43:4c1e4e94cdd3 2151 connection->on_connection_close_received_event_subscription.context = context;
AzureIoTClient 43:4c1e4e94cdd3 2152
AzureIoTClient 43:4c1e4e94cdd3 2153 /* Codes_S_R_S_CONNECTION_01_276: [ On success, `connection_subscribe_on_connection_close_received` shall return a non-NULL handle to the event subcription. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2154 result = &connection->on_connection_close_received_event_subscription;
AzureIoTClient 43:4c1e4e94cdd3 2155 }
AzureIoTClient 43:4c1e4e94cdd3 2156 }
AzureIoTClient 43:4c1e4e94cdd3 2157
AzureIoTClient 43:4c1e4e94cdd3 2158 return result;
AzureIoTClient 43:4c1e4e94cdd3 2159 }
AzureIoTClient 43:4c1e4e94cdd3 2160
AzureIoTClient 43:4c1e4e94cdd3 2161 void connection_unsubscribe_on_connection_close_received(ON_CONNECTION_CLOSED_EVENT_SUBSCRIPTION_HANDLE event_subscription)
AzureIoTClient 43:4c1e4e94cdd3 2162 {
AzureIoTClient 43:4c1e4e94cdd3 2163 if (event_subscription == NULL)
AzureIoTClient 43:4c1e4e94cdd3 2164 {
AzureIoTClient 43:4c1e4e94cdd3 2165 LogError("NULL event_subscription");
AzureIoTClient 43:4c1e4e94cdd3 2166 }
AzureIoTClient 43:4c1e4e94cdd3 2167 else
AzureIoTClient 43:4c1e4e94cdd3 2168 {
AzureIoTClient 43:4c1e4e94cdd3 2169 /* Codes_S_R_S_CONNECTION_01_281: [ `connection_unsubscribe_on_connection_close_received` shall remove the subscription for the connection closed event that was made by calling `connection_subscribe_on_connection_close_received`. ]*/
AzureIoTClient 43:4c1e4e94cdd3 2170 event_subscription->on_connection_close_received = NULL;
AzureIoTClient 43:4c1e4e94cdd3 2171 event_subscription->context = NULL;
AzureIoTClient 43:4c1e4e94cdd3 2172 }
AzureIoTClient 43:4c1e4e94cdd3 2173 }