A small memory footprint AMQP implimentation

Dependents:   iothub_client_sample_amqp remote_monitoring simplesample_amqp

Committer:
AzureIoTClient
Date:
Mon May 08 10:50:45 2017 -0700
Revision:
24:2c59c2d43ebf
Parent:
23:1111ee8bcba4
Child:
25:1101516ee67d
1.1.14

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