A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Committer:
AzureIoTClient
Date:
Fri Nov 03 13:18:57 2017 -0700
Revision:
35:d0bed2404ee9
Parent:
30:0407b2db334c
Child:
38:7631b92cc772
1.1.27

Who changed what in which revision?

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